LCOV - code coverage report
Current view: top level - spdk/module/vfu_device - vfu_virtio.c (source / functions) Hit Total Coverage
Test: Combined Lines: 632 866 73.0 %
Date: 2024-08-10 15:37:42 Functions: 47 52 90.4 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 375 683 54.9 %

           Branch data     Line data    Source code
       1                 :            : /*   SPDX-License-Identifier: BSD-3-Clause
       2                 :            :  *   Copyright (C) 2022 Intel Corporation.
       3                 :            :  *   All rights reserved.
       4                 :            :  */
       5                 :            : 
       6                 :            : /*
       7                 :            :  * virtio over vfio-user common library
       8                 :            :  */
       9                 :            : #include "spdk/env.h"
      10                 :            : #include "spdk/bdev.h"
      11                 :            : #include "spdk/bdev_module.h"
      12                 :            : #include "spdk/stdinc.h"
      13                 :            : #include "spdk/assert.h"
      14                 :            : #include "spdk/barrier.h"
      15                 :            : #include "spdk/thread.h"
      16                 :            : #include "spdk/memory.h"
      17                 :            : #include "spdk/util.h"
      18                 :            : #include "spdk/log.h"
      19                 :            : #include "spdk/string.h"
      20                 :            : #include "spdk/likely.h"
      21                 :            : 
      22                 :            : #include "vfu_virtio_internal.h"
      23                 :            : 
      24                 :            : static int vfu_virtio_dev_start(struct vfu_virtio_dev *dev);
      25                 :            : static int vfu_virtio_dev_stop(struct vfu_virtio_dev *dev);
      26                 :            : 
      27                 :            : static inline void
      28                 :        114 : vfu_virtio_unmap_q(struct vfu_virtio_dev *dev, struct q_mapping *mapping)
      29                 :            : {
      30                 :        114 :         struct vfu_virtio_endpoint *virtio_endpoint = dev->virtio_endpoint;
      31                 :            : 
      32         [ +  + ]:        114 :         if (mapping->addr != NULL) {
      33                 :         78 :                 spdk_vfu_unmap_sg(virtio_endpoint->endpoint, mapping->sg,
      34                 :            :                                   &mapping->iov, 1);
      35                 :         78 :                 mapping->addr = NULL;
      36                 :         78 :                 mapping->len = 0;
      37                 :            :         }
      38                 :        114 : }
      39                 :            : 
      40                 :            : static inline int
      41                 :         98 : vfu_virtio_map_q(struct vfu_virtio_dev *dev, struct q_mapping *mapping, uint64_t phys_addr,
      42                 :            :                  uint64_t len)
      43                 :            : {
      44                 :         98 :         struct vfu_virtio_endpoint *virtio_endpoint = dev->virtio_endpoint;
      45                 :            :         void *addr;
      46                 :            : 
      47   [ +  -  +  -  :         98 :         if (!mapping->addr && len && phys_addr) {
                   +  - ]
      48                 :         98 :                 addr = spdk_vfu_map_one(virtio_endpoint->endpoint, phys_addr, len,
      49                 :            :                                         mapping->sg, &mapping->iov, PROT_READ | PROT_WRITE);
      50         [ +  + ]:         98 :                 if (addr == NULL) {
      51                 :         20 :                         return -EINVAL;
      52                 :            :                 }
      53                 :         78 :                 mapping->phys_addr = phys_addr;
      54                 :         78 :                 mapping->len = len;
      55                 :         78 :                 mapping->addr = addr;
      56                 :            :         }
      57                 :            : 
      58                 :         78 :         return 0;
      59                 :            : }
      60                 :            : 
      61                 :            : static int
      62                 :        220 : virtio_dev_map_vq(struct vfu_virtio_dev *dev, struct vfu_virtio_vq *vq)
      63                 :            : {
      64                 :            :         int ret;
      65                 :            :         uint64_t phys_addr, len;
      66                 :            : 
      67   [ -  +  +  +  :        220 :         if (!vq->enabled || (vq->q_state == VFU_VQ_ACTIVE)) {
                   +  + ]
      68                 :        174 :                 return 0;
      69                 :            :         }
      70                 :            : 
      71   [ -  +  +  + ]:         46 :         SPDK_DEBUGLOG(vfu_virtio, "%s: try to map vq %u\n", dev->name, vq->id);
      72                 :            : 
      73                 :         46 :         len = virtio_queue_desc_size(dev, vq);
      74                 :         46 :         phys_addr = ((((uint64_t)vq->desc_hi) << 32) | vq->desc_lo);
      75                 :         46 :         ret = vfu_virtio_map_q(dev, &vq->desc, phys_addr, len);
      76         [ +  + ]:         46 :         if (ret) {
      77   [ -  +  -  + ]:         20 :                 SPDK_DEBUGLOG(vfu_virtio, "Error to map descs\n");
      78                 :         20 :                 return ret;
      79                 :            :         }
      80                 :            : 
      81                 :         26 :         len = virtio_queue_avail_size(dev, vq);
      82                 :         26 :         phys_addr = ((((uint64_t)vq->avail_hi) << 32) | vq->avail_lo);
      83                 :         26 :         ret = vfu_virtio_map_q(dev, &vq->avail, phys_addr, len);
      84         [ -  + ]:         26 :         if (ret) {
      85                 :          0 :                 vfu_virtio_unmap_q(dev, &vq->desc);
      86   [ #  #  #  # ]:          0 :                 SPDK_DEBUGLOG(vfu_virtio, "Error to map available ring\n");
      87                 :          0 :                 return ret;
      88                 :            :         }
      89                 :            : 
      90                 :         26 :         len = virtio_queue_used_size(dev, vq);
      91                 :         26 :         phys_addr = ((((uint64_t)vq->used_hi) << 32) | vq->used_lo);
      92                 :         26 :         ret = vfu_virtio_map_q(dev, &vq->used, phys_addr, len);
      93         [ -  + ]:         26 :         if (ret) {
      94                 :          0 :                 vfu_virtio_unmap_q(dev, &vq->desc);
      95                 :          0 :                 vfu_virtio_unmap_q(dev, &vq->avail);
      96   [ #  #  #  # ]:          0 :                 SPDK_DEBUGLOG(vfu_virtio, "Error to map used ring\n");
      97                 :          0 :                 return ret;
      98                 :            :         }
      99                 :            : 
     100                 :            :         /* We're running with polling mode */
     101         [ +  + ]:         26 :         if (virtio_guest_has_feature(dev, VIRTIO_F_RING_PACKED)) {
     102                 :         12 :                 vq->used.device_event->flags = VRING_PACKED_EVENT_FLAG_DISABLE;
     103                 :            :         } else {
     104                 :         14 :                 vq->used.used->flags = VRING_USED_F_NO_NOTIFY;
     105                 :            :         }
     106                 :            : 
     107   [ -  +  +  + ]:         26 :         SPDK_DEBUGLOG(vfu_virtio, "%s: map vq %u successfully\n", dev->name, vq->id);
     108                 :         26 :         vq->q_state = VFU_VQ_ACTIVE;
     109                 :            : 
     110                 :         26 :         return 0;
     111                 :            : }
     112                 :            : 
     113                 :            : static void
     114                 :         38 : virtio_dev_unmap_vq(struct vfu_virtio_dev *dev, struct vfu_virtio_vq *vq)
     115                 :            : {
     116   [ -  +  +  + ]:         38 :         SPDK_DEBUGLOG(vfu_virtio, "%s: unmap vq %u\n", dev->name, vq->id);
     117                 :         38 :         vq->q_state = VFU_VQ_INACTIVE;
     118                 :            : 
     119                 :         38 :         vfu_virtio_unmap_q(dev, &vq->desc);
     120                 :         38 :         vfu_virtio_unmap_q(dev, &vq->avail);
     121                 :         38 :         vfu_virtio_unmap_q(dev, &vq->used);
     122                 :         38 : }
     123                 :            : 
     124                 :            : static bool
     125                 :        118 : vfu_virtio_vq_should_unmap(struct vfu_virtio_vq *vq, void *map_start, void *map_end)
     126                 :            : {
     127                 :            :         /* always do unmap when stopping the device */
     128   [ +  +  -  + ]:        118 :         if (!map_start || !map_end) {
     129                 :         22 :                 return true;
     130                 :            :         }
     131                 :            : 
     132   [ +  +  +  - ]:         96 :         if (vq->desc.addr >= map_start && vq->desc.addr < map_end) {
     133                 :         16 :                 return true;
     134                 :            :         }
     135                 :            : 
     136   [ -  +  -  - ]:         80 :         if (vq->avail.addr >= map_start && vq->avail.addr < map_end) {
     137                 :          0 :                 return true;
     138                 :            :         }
     139                 :            : 
     140   [ -  +  -  - ]:         80 :         if (vq->used.addr >= map_start && vq->used.addr < map_end) {
     141                 :          0 :                 return true;
     142                 :            :         }
     143                 :            : 
     144                 :         80 :         return false;
     145                 :            : }
     146                 :            : 
     147                 :            : static void
     148                 :         76 : vfu_virtio_dev_unmap_vqs(struct vfu_virtio_dev *dev, void *map_start, void *map_end)
     149                 :            : {
     150                 :            :         uint32_t i;
     151                 :            :         struct vfu_virtio_vq *vq;
     152                 :            : 
     153         [ +  + ]:        304 :         for (i = 0; i < dev->num_queues; i++) {
     154                 :        228 :                 vq = &dev->vqs[i];
     155   [ -  +  +  + ]:        228 :                 if (!vq->enabled) {
     156                 :        110 :                         continue;
     157                 :            :                 }
     158                 :            : 
     159         [ +  + ]:        118 :                 if (!vfu_virtio_vq_should_unmap(vq, map_start, map_end)) {
     160                 :         80 :                         continue;
     161                 :            :                 }
     162                 :         38 :                 virtio_dev_unmap_vq(dev, vq);
     163                 :            :         }
     164                 :         76 : }
     165                 :            : 
     166                 :            : /* This function is used to notify VM that the device
     167                 :            :  * configuration space has been changed.
     168                 :            :  */
     169                 :            : void
     170                 :          0 : vfu_virtio_notify_config(struct vfu_virtio_endpoint *virtio_endpoint)
     171                 :            : {
     172                 :          0 :         struct spdk_vfu_endpoint *endpoint = virtio_endpoint->endpoint;
     173                 :            : 
     174         [ #  # ]:          0 :         if (virtio_endpoint->dev == NULL) {
     175                 :          0 :                 return;
     176                 :            :         }
     177                 :            : 
     178                 :          0 :         virtio_endpoint->dev->cfg.isr = 1;
     179                 :          0 :         virtio_endpoint->dev->cfg.config_generation++;
     180                 :            : 
     181                 :          0 :         vfu_irq_trigger(spdk_vfu_get_vfu_ctx(endpoint), virtio_endpoint->dev->cfg.msix_config);
     182                 :            : }
     183                 :            : 
     184                 :            : static void
     185                 :         22 : vfu_virtio_dev_reset(struct vfu_virtio_dev *dev)
     186                 :            : {
     187                 :            :         uint32_t i;
     188                 :            :         struct vfu_virtio_vq *vq;
     189                 :            : 
     190   [ -  +  +  + ]:         22 :         SPDK_DEBUGLOG(vfu_virtio, "device %s resetting\n", dev->name);
     191                 :            : 
     192         [ +  + ]:         88 :         for (i = 0; i < dev->num_queues; i++) {
     193                 :         66 :                 vq = &dev->vqs[i];
     194                 :            : 
     195                 :         66 :                 vq->q_state = VFU_VQ_CREATED;
     196                 :         66 :                 vq->vector = 0;
     197                 :         66 :                 vq->enabled = false;
     198                 :         66 :                 vq->last_avail_idx = 0;
     199                 :         66 :                 vq->last_used_idx = 0;
     200                 :            : 
     201                 :         66 :                 vq->packed.packed_ring = false;
     202                 :         66 :                 vq->packed.avail_phase = 0;
     203                 :         66 :                 vq->packed.used_phase = 0;
     204                 :            :         }
     205                 :            : 
     206         [ -  + ]:         22 :         memset(&dev->cfg, 0, sizeof(struct virtio_pci_cfg));
     207                 :         22 : }
     208                 :            : 
     209                 :            : static int
     210                 :         48 : virtio_dev_set_status(struct vfu_virtio_dev *dev, uint8_t status)
     211                 :            : {
     212                 :         48 :         int ret = 0;
     213                 :            : 
     214   [ -  +  +  + ]:         48 :         SPDK_DEBUGLOG(vfu_virtio, "device current status %x, set status %x\n", dev->cfg.device_status,
     215                 :            :                       status);
     216                 :            : 
     217         [ +  + ]:         48 :         if (!(virtio_dev_is_started(dev))) {
     218         [ +  + ]:         42 :                 if (status & VIRTIO_CONFIG_S_DRIVER_OK) {
     219                 :         10 :                         ret = vfu_virtio_dev_start(dev);
     220                 :            :                 }
     221                 :            :         } else {
     222         [ +  - ]:          6 :                 if (!(status & VIRTIO_CONFIG_S_DRIVER_OK)) {
     223                 :          6 :                         ret = vfu_virtio_dev_stop(dev);
     224                 :            :                 }
     225                 :            :         }
     226                 :            : 
     227         [ -  + ]:         48 :         if (ret) {
     228                 :          0 :                 SPDK_ERRLOG("Failed to start/stop device\n");
     229                 :          0 :                 return ret;
     230                 :            :         }
     231                 :            : 
     232                 :         48 :         dev->cfg.device_status = status;
     233                 :            : 
     234         [ +  + ]:         48 :         if (status == 0) {
     235                 :         12 :                 vfu_virtio_dev_reset(dev);
     236                 :            :         }
     237                 :            : 
     238                 :         48 :         return 0;
     239                 :            : }
     240                 :            : 
     241                 :            : static int
     242                 :         20 : virtio_dev_set_features(struct vfu_virtio_dev *dev, uint64_t features)
     243                 :            : {
     244         [ -  + ]:         20 :         if (dev->cfg.device_status & VIRTIO_CONFIG_S_FEATURES_OK) {
     245                 :          0 :                 SPDK_ERRLOG("Feature negotiation has finished\n");
     246                 :          0 :                 return -EINVAL;
     247                 :            :         }
     248                 :            : 
     249         [ -  + ]:         20 :         if (features & ~dev->host_features) {
     250                 :          0 :                 SPDK_ERRLOG("Host features 0x%"PRIx64", guest features 0x%"PRIx64"\n",
     251                 :            :                             dev->host_features, features);
     252                 :          0 :                 return -ENOTSUP;
     253                 :            :         }
     254                 :            : 
     255   [ -  +  +  + ]:         20 :         SPDK_DEBUGLOG(vfu_virtio, "%s: negotiated features 0x%"PRIx64"\n", dev->name,
     256                 :            :                       features);
     257                 :         20 :         dev->cfg.guest_features = features;
     258                 :            : 
     259                 :         20 :         return 0;
     260                 :            : }
     261                 :            : 
     262                 :            : static int
     263                 :         22 : virtio_dev_enable_vq(struct vfu_virtio_dev *dev, uint16_t qid)
     264                 :            : {
     265                 :            :         struct vfu_virtio_vq *vq;
     266                 :            : 
     267   [ -  +  +  + ]:         22 :         SPDK_DEBUGLOG(vfu_virtio, "%s: enable vq %u\n", dev->name, qid);
     268                 :            : 
     269                 :         22 :         vq = &dev->vqs[qid];
     270   [ -  +  -  + ]:         22 :         if (vq->enabled) {
     271                 :          0 :                 SPDK_ERRLOG("Queue %u is enabled\n", qid);
     272                 :          0 :                 return -EINVAL;
     273                 :            :         }
     274                 :         22 :         vq->enabled = true;
     275                 :            : 
     276         [ -  + ]:         22 :         if (virtio_dev_map_vq(dev, vq)) {
     277                 :          0 :                 SPDK_ERRLOG("Queue %u failed to map\n", qid);
     278                 :          0 :                 return 0;
     279                 :            :         }
     280                 :            : 
     281                 :         22 :         vq->avail.avail->idx = 0;
     282                 :         22 :         vq->last_avail_idx = 0;
     283                 :         22 :         vq->used.used->idx = 0;
     284                 :         22 :         vq->last_used_idx = 0;
     285                 :            : 
     286         [ +  + ]:         22 :         if (virtio_guest_has_feature(dev, VIRTIO_F_RING_PACKED)) {
     287   [ -  +  -  + ]:         12 :                 SPDK_DEBUGLOG(vfu_virtio, "%s: vq %u PACKED RING ENABLED\n", dev->name, qid);
     288                 :         12 :                 vq->packed.packed_ring = true;
     289                 :         12 :                 vq->packed.avail_phase = true;
     290                 :         12 :                 vq->packed.used_phase = true;
     291                 :            :         }
     292                 :            : 
     293                 :         22 :         return 0;
     294                 :            : }
     295                 :            : 
     296                 :            : static int
     297                 :          6 : virtio_dev_disable_vq(struct vfu_virtio_dev *dev, uint16_t qid)
     298                 :            : {
     299                 :            :         struct vfu_virtio_vq *vq;
     300                 :            : 
     301   [ -  +  +  - ]:          6 :         SPDK_DEBUGLOG(vfu_virtio, "%s: disable vq %u\n", dev->name, qid);
     302                 :            : 
     303                 :          6 :         vq = &dev->vqs[qid];
     304   [ -  +  +  - ]:          6 :         if (!vq->enabled) {
     305                 :          6 :                 SPDK_NOTICELOG("Queue %u isn't enabled\n", qid);
     306                 :          6 :                 return 0;
     307                 :            :         }
     308                 :            : 
     309                 :          0 :         virtio_dev_unmap_vq(dev, vq);
     310                 :            : 
     311                 :          0 :         vq->q_state = VFU_VQ_CREATED;
     312                 :          0 :         vq->vector = 0;
     313                 :          0 :         vq->enabled = false;
     314                 :          0 :         vq->last_avail_idx = 0;
     315                 :          0 :         vq->last_used_idx = 0;
     316                 :          0 :         vq->packed.packed_ring = false;
     317                 :          0 :         vq->packed.avail_phase = 0;
     318                 :          0 :         vq->packed.used_phase = 0;
     319                 :            : 
     320                 :          0 :         return 0;
     321                 :            : }
     322                 :            : 
     323                 :            : static int
     324                 :    2516589 : virtio_dev_split_get_avail_reqs(struct vfu_virtio_dev *dev, struct vfu_virtio_vq *vq,
     325                 :            :                                 uint16_t *reqs, uint16_t max_reqs)
     326                 :            : {
     327                 :            :         uint16_t count, i, avail_idx, last_idx;
     328                 :            : 
     329                 :    2516589 :         last_idx = vq->last_avail_idx;
     330                 :    2516589 :         avail_idx = vq->avail.avail->idx;
     331                 :            : 
     332                 :    2516589 :         spdk_smp_rmb();
     333                 :            : 
     334                 :    2516589 :         count = avail_idx - last_idx;
     335         [ +  + ]:    2516589 :         if (count == 0) {
     336                 :    2442236 :                 return 0;
     337                 :            :         }
     338                 :            : 
     339                 :      74353 :         count = spdk_min(count, max_reqs);
     340                 :      74353 :         vq->last_avail_idx += count;
     341                 :            : 
     342         [ +  + ]:    2434820 :         for (i = 0; i < count; i++) {
     343                 :    2360467 :                 reqs[i] = vq->avail.avail->ring[(last_idx + i) & (vq->qsize - 1)];
     344                 :            :         }
     345                 :            : 
     346   [ -  +  -  + ]:      74353 :         SPDK_DEBUGLOG(vfu_virtio_io,
     347                 :            :                       "AVAIL: vq %u last_idx=%"PRIu16" avail_idx=%"PRIu16" count=%"PRIu16"\n",
     348                 :            :                       vq->id, last_idx, avail_idx, count);
     349                 :            : 
     350                 :      74353 :         return count;
     351                 :            : }
     352                 :            : 
     353                 :            : static int
     354                 :    7081397 : virtio_vring_split_desc_get_next(struct vring_desc **desc,
     355                 :            :                                  struct vring_desc *desc_table,
     356                 :            :                                  uint32_t desc_table_size)
     357                 :            : {
     358                 :    7081397 :         struct vring_desc *old_desc = *desc;
     359                 :            :         uint16_t next_idx;
     360                 :            : 
     361         [ +  + ]:    7081397 :         if ((old_desc->flags & VRING_DESC_F_NEXT) == 0) {
     362                 :    2360467 :                 *desc = NULL;
     363                 :    2360467 :                 return 0;
     364                 :            :         }
     365                 :            : 
     366                 :    4720930 :         next_idx = old_desc->next;
     367         [ -  + ]:    4720930 :         if (spdk_unlikely(next_idx >= desc_table_size)) {
     368                 :          0 :                 *desc = NULL;
     369                 :          0 :                 return -1;
     370                 :            :         }
     371                 :            : 
     372                 :    4720930 :         *desc = &desc_table[next_idx];
     373                 :    4720930 :         return 0;
     374                 :            : }
     375                 :            : 
     376                 :            : static inline void *
     377                 :    7081397 : virtio_vring_desc_to_iov(struct vfu_virtio_dev *dev, struct vring_desc *desc,
     378                 :            :                          dma_sg_t *sg, struct iovec *iov)
     379                 :            : {
     380                 :    7081397 :         struct vfu_virtio_endpoint *virtio_endpoint = dev->virtio_endpoint;
     381                 :            : 
     382                 :    7081397 :         return spdk_vfu_map_one(virtio_endpoint->endpoint, desc->addr, desc->len,
     383                 :            :                                 sg, iov, PROT_READ | PROT_WRITE);
     384                 :            : }
     385                 :            : 
     386                 :            : static int
     387                 :    2360467 : virtio_split_vring_get_desc(struct vfu_virtio_dev *dev, struct vfu_virtio_vq *vq, uint16_t desc_idx,
     388                 :            :                             struct vring_desc **desc, struct vring_desc **desc_table,
     389                 :            :                             uint32_t *desc_table_size,
     390                 :            :                             dma_sg_t *sg, struct iovec *iov)
     391                 :            : {
     392                 :    2360467 :         *desc = &vq->desc.desc[desc_idx];
     393                 :            : 
     394         [ -  + ]:    2360467 :         if (virtio_vring_split_desc_is_indirect(*desc)) {
     395                 :          0 :                 *desc_table_size = (*desc)->len / sizeof(struct vring_desc);
     396                 :          0 :                 *desc_table = virtio_vring_desc_to_iov(dev, *desc, sg, iov);
     397                 :          0 :                 *desc = *desc_table;
     398         [ #  # ]:          0 :                 if (*desc == NULL) {
     399                 :          0 :                         return -EINVAL;
     400                 :            :                 }
     401                 :          0 :                 return 0;
     402                 :            :         }
     403                 :            : 
     404                 :    2360467 :         *desc_table = vq->desc.desc;
     405                 :    2360467 :         *desc_table_size = vq->qsize;
     406                 :            : 
     407                 :    2360467 :         return 0;
     408                 :            : }
     409                 :            : 
     410                 :            : static inline dma_sg_t *
     411                 :    9756867 : virtio_req_to_sg_t(struct vfu_virtio_req *req, uint32_t iovcnt)
     412                 :            : {
     413                 :    9756867 :         return (dma_sg_t *)(req->sg + iovcnt * dma_sg_size());
     414                 :            : }
     415                 :            : 
     416                 :            : static inline struct vfu_virtio_req *
     417                 :    2410317 : vfu_virtio_dev_get_req(struct vfu_virtio_endpoint *virtio_endpoint, struct vfu_virtio_vq *vq)
     418                 :            : {
     419                 :            :         struct vfu_virtio_req *req;
     420                 :            : 
     421                 :    2410317 :         req = STAILQ_FIRST(&vq->free_reqs);
     422         [ -  + ]:    2410317 :         if (req == NULL) {
     423                 :          0 :                 return NULL;
     424                 :            :         }
     425         [ -  + ]:    2410317 :         STAILQ_REMOVE_HEAD(&vq->free_reqs, link);
     426                 :            : 
     427                 :    2410317 :         req->iovcnt = 0;
     428                 :    2410317 :         req->used_len = 0;
     429                 :    2410317 :         req->payload_size = 0;
     430                 :    2410317 :         req->req_idx = 0;
     431                 :    2410317 :         req->buffer_id = 0;
     432                 :    2410317 :         req->num_descs = 0;
     433                 :            : 
     434                 :    2410317 :         return req;
     435                 :            : }
     436                 :            : 
     437                 :            : void
     438                 :    2410317 : vfu_virtio_dev_put_req(struct vfu_virtio_req *req)
     439                 :            : {
     440                 :    2410317 :         struct vfu_virtio_dev *dev = req->dev;
     441                 :    2410317 :         struct vfu_virtio_endpoint *virtio_endpoint = dev->virtio_endpoint;
     442                 :    2410317 :         vfu_ctx_t *vfu_ctx = spdk_vfu_get_vfu_ctx(virtio_endpoint->endpoint);
     443                 :            : 
     444         [ +  + ]:    2410317 :         if (req->indirect_iov->iov_base) {
     445                 :      49850 :                 vfu_sgl_put(vfu_ctx, req->indirect_sg, req->indirect_iov, 1);
     446                 :      49850 :                 req->indirect_iov->iov_base = NULL;
     447                 :      49850 :                 req->indirect_iov->iov_len = 0;
     448                 :            :         }
     449                 :            : 
     450         [ +  - ]:    2410317 :         if (req->iovcnt) {
     451                 :    2410317 :                 vfu_sgl_put(vfu_ctx, virtio_req_to_sg_t(req, 0), req->iovs, req->iovcnt);
     452                 :    2410317 :                 req->iovcnt = 0;
     453                 :            :         }
     454                 :            : 
     455         [ -  + ]:    2410317 :         STAILQ_INSERT_HEAD(&req->vq->free_reqs, req, link);
     456                 :    2410317 : }
     457                 :            : 
     458                 :            : void
     459                 :    2410317 : vfu_virtio_finish_req(struct vfu_virtio_req *req)
     460                 :            : {
     461                 :    2410317 :         struct vfu_virtio_dev *dev = req->dev;
     462                 :    2410317 :         struct vfu_virtio_endpoint *virtio_endpoint = dev->virtio_endpoint;
     463                 :            : 
     464         [ -  + ]:    2410317 :         assert(virtio_endpoint->io_outstanding);
     465                 :    2410317 :         virtio_endpoint->io_outstanding--;
     466                 :            : 
     467         [ +  + ]:    2410317 :         if (!virtio_guest_has_feature(req->dev, VIRTIO_F_RING_PACKED)) {
     468                 :    2360467 :                 virtio_vq_used_ring_split_enqueue(req->vq, req->req_idx, req->used_len);
     469                 :            :         } else {
     470                 :      49850 :                 virtio_vq_used_ring_packed_enqueue(req->vq, req->buffer_id, req->num_descs, req->used_len);
     471                 :            :         }
     472                 :            : 
     473                 :    2410317 :         vfu_virtio_dev_put_req(req);
     474                 :    2410317 : }
     475                 :            : 
     476                 :            : static inline void
     477                 :          6 : vfu_virtio_dev_free_reqs(struct vfu_virtio_endpoint *virtio_endpoint, struct vfu_virtio_dev *dev)
     478                 :            : {
     479                 :            :         struct vfu_virtio_req *req;
     480                 :            :         struct vfu_virtio_vq *vq;
     481                 :            :         uint32_t i;
     482                 :            : 
     483         [ +  + ]:         24 :         for (i = 0; i < dev->num_queues; i++) {
     484                 :         18 :                 vq = &dev->vqs[i];
     485         [ +  + ]:       7716 :                 while (!STAILQ_EMPTY(&vq->free_reqs)) {
     486                 :       7698 :                         req = STAILQ_FIRST(&vq->free_reqs);
     487         [ +  + ]:       7698 :                         STAILQ_REMOVE_HEAD(&vq->free_reqs, link);
     488                 :       7698 :                         vfu_virtio_vq_free_req(virtio_endpoint, vq, req);
     489                 :            :                 }
     490                 :            :         }
     491                 :          6 : }
     492                 :            : 
     493                 :            : static int
     494                 :    2360467 : virtio_dev_split_iovs_setup(struct vfu_virtio_dev *dev, struct vfu_virtio_vq *vq,
     495                 :            :                             uint16_t desc_idx, struct vfu_virtio_req *req)
     496                 :            : {
     497                 :    2360467 :         struct vring_desc *desc, *desc_table;
     498                 :    2360467 :         uint32_t desc_table_size, len = 0;
     499                 :    2360467 :         uint32_t desc_handled_cnt = 0;
     500                 :            :         int rc;
     501                 :            : 
     502                 :    2360467 :         rc = virtio_split_vring_get_desc(dev, vq, desc_idx, &desc,
     503                 :            :                                          &desc_table, &desc_table_size,
     504                 :            :                                          req->indirect_sg, req->indirect_iov);
     505         [ -  + ]:    2360467 :         if (spdk_unlikely(rc)) {
     506                 :          0 :                 SPDK_ERRLOG("Invalid descriptor at index %"PRIu16".\n", desc_idx);
     507                 :          0 :                 return rc;
     508                 :            :         }
     509                 :            : 
     510         [ -  + ]:    2360467 :         assert(req->iovcnt == 0);
     511                 :            : 
     512                 :            :         while (true) {
     513         [ -  + ]:    7081397 :                 if (spdk_unlikely(!virtio_vring_desc_to_iov(dev, desc, virtio_req_to_sg_t(req, req->iovcnt),
     514                 :            :                                   &req->iovs[req->iovcnt]))) {
     515                 :          0 :                         return -EINVAL;
     516                 :            :                 }
     517                 :    7081397 :                 req->desc_writeable[req->iovcnt] = false;
     518         [ +  + ]:    7081397 :                 if (virtio_vring_split_desc_is_wr(desc)) {
     519                 :    3543054 :                         req->desc_writeable[req->iovcnt] = true;
     520                 :            :                 }
     521                 :            : 
     522                 :    7081397 :                 req->iovcnt++;
     523                 :    7081397 :                 len += desc->len;
     524                 :            : 
     525                 :    7081397 :                 rc = virtio_vring_split_desc_get_next(&desc, desc_table, desc_table_size);
     526         [ -  + ]:    7081397 :                 if (spdk_unlikely(rc)) {
     527                 :          0 :                         return rc;
     528         [ +  + ]:    7081397 :                 } else if (desc == NULL) {
     529                 :    2360467 :                         break;
     530                 :            :                 }
     531                 :            : 
     532                 :    4720930 :                 desc_handled_cnt++;
     533         [ -  + ]:    4720930 :                 if (spdk_unlikely(desc_handled_cnt > desc_table_size)) {
     534                 :          0 :                         return -EINVAL;
     535                 :            :                 }
     536                 :            :         }
     537                 :            : 
     538                 :    2360467 :         req->payload_size = len;
     539                 :            : 
     540                 :    2360467 :         return 0;
     541                 :            : }
     542                 :            : 
     543                 :            : void
     544                 :    2360467 : virtio_vq_used_ring_split_enqueue(struct vfu_virtio_vq *vq, uint16_t req_idx, uint32_t used_len)
     545                 :            : {
     546                 :    2360467 :         uint16_t last_idx = vq->last_used_idx & (vq->qsize - 1);
     547                 :            : 
     548   [ -  +  -  + ]:    2360467 :         SPDK_DEBUGLOG(vfu_virtio_io,
     549                 :            :                       "Queue %u - USED RING: last_idx=%"PRIu16" req_idx=%"PRIu16" used_len=%"PRIu32"\n",
     550                 :            :                       vq->id, last_idx, req_idx, used_len);
     551                 :            : 
     552                 :    2360467 :         vq->used.used->ring[last_idx].id = req_idx;
     553                 :    2360467 :         vq->used.used->ring[last_idx].len = used_len;
     554                 :    2360467 :         vq->last_used_idx++;
     555                 :            : 
     556                 :    2360467 :         spdk_smp_wmb();
     557                 :            : 
     558                 :    2360467 :         *(volatile uint16_t *)&vq->used.used->idx = vq->last_used_idx;
     559                 :            : 
     560                 :    2360467 :         vq->used_req_cnt++;
     561                 :    2360467 : }
     562                 :            : 
     563                 :            : void
     564                 :      49850 : virtio_vq_used_ring_packed_enqueue(struct vfu_virtio_vq *vq, uint16_t buffer_id, uint32_t num_descs,
     565                 :            :                                    uint32_t used_len)
     566                 :            : {
     567                 :      49850 :         struct vring_packed_desc *desc = &vq->desc.desc_packed[vq->last_used_idx];
     568                 :            : 
     569   [ -  +  -  + ]:      49850 :         SPDK_DEBUGLOG(vfu_virtio_io,
     570                 :            :                       "Queue %u - USED RING: buffer_id=%"PRIu16" num_descs=%u used_len=%"PRIu32"\n",
     571                 :            :                       vq->id, buffer_id, num_descs, used_len);
     572                 :            : 
     573         [ -  + ]:      49850 :         if (spdk_unlikely(virtio_vring_packed_is_used(desc, vq->packed.used_phase))) {
     574                 :          0 :                 SPDK_ERRLOG("descriptor has been used before\n");
     575                 :          0 :                 return;
     576                 :            :         }
     577                 :            : 
     578                 :            :         /* In used desc addr is unused and len specifies the buffer length
     579                 :            :          * that has been written to by the device.
     580                 :            :          */
     581                 :      49850 :         desc->addr = 0;
     582                 :      49850 :         desc->len = used_len;
     583                 :            : 
     584                 :            :         /* This bit specifies whether any data has been written by the device */
     585         [ +  + ]:      49850 :         if (used_len != 0) {
     586                 :      49844 :                 desc->flags |= VRING_DESC_F_WRITE;
     587                 :            :         }
     588                 :            : 
     589                 :            :         /* Buffer ID is included in the last descriptor in the list.
     590                 :            :          * The driver needs to keep track of the size of the list corresponding
     591                 :            :          * to each buffer ID.
     592                 :            :          */
     593                 :      49850 :         desc->id = buffer_id;
     594                 :            : 
     595                 :            :         /* A device MUST NOT make the descriptor used before buffer_id is
     596                 :            :          * written to the descriptor.
     597                 :            :          */
     598                 :      49850 :         spdk_smp_wmb();
     599                 :            : 
     600                 :            :         /* To mark a desc as used, the device sets the F_USED bit in flags to match
     601                 :            :          * the internal Device ring wrap counter. It also sets the F_AVAIL bit to
     602                 :            :          * match the same value.
     603                 :            :          */
     604         [ +  + ]:      49850 :         if (vq->packed.used_phase) {
     605                 :      25510 :                 desc->flags |= (1 << VRING_PACKED_DESC_F_AVAIL);
     606                 :      25510 :                 desc->flags |= (1 << VRING_PACKED_DESC_F_USED);
     607                 :            :         } else {
     608                 :      24340 :                 desc->flags &= ~(1 << VRING_PACKED_DESC_F_AVAIL);
     609                 :      24340 :                 desc->flags &= ~(1 << VRING_PACKED_DESC_F_USED);
     610                 :            :         }
     611                 :            : 
     612                 :      49850 :         vq->last_used_idx += num_descs;
     613         [ +  + ]:      49850 :         if (vq->last_used_idx >= vq->qsize) {
     614                 :        132 :                 vq->last_used_idx -= vq->qsize;
     615                 :        132 :                 vq->packed.used_phase = !vq->packed.used_phase;
     616                 :            :         }
     617                 :            : 
     618                 :      49850 :         vq->used_req_cnt++;
     619                 :            : }
     620                 :            : 
     621                 :            : static int
     622                 :      17769 : vfu_virtio_vq_post_irq(struct vfu_virtio_dev *dev, struct vfu_virtio_vq *vq)
     623                 :            : {
     624                 :      17769 :         struct vfu_virtio_endpoint *virtio_endpoint = dev->virtio_endpoint;
     625                 :      17769 :         vfu_ctx_t *vfu_ctx = spdk_vfu_get_vfu_ctx(virtio_endpoint->endpoint);
     626                 :            : 
     627                 :      17769 :         vq->used_req_cnt = 0;
     628                 :            : 
     629         [ +  - ]:      17769 :         if (spdk_vfu_endpoint_msix_enabled(virtio_endpoint->endpoint)) {
     630   [ -  +  -  + ]:      17769 :                 SPDK_DEBUGLOG(vfu_virtio_io, "%s: Queue %u post MSIX IV %u\n",
     631                 :            :                               spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint),
     632                 :            :                               vq->id, vq->vector);
     633                 :      17769 :                 return vfu_irq_trigger(vfu_ctx, vq->vector);
     634                 :            :         } else {
     635         [ #  # ]:          0 :                 if (!spdk_vfu_endpoint_intx_enabled(virtio_endpoint->endpoint)) {
     636   [ #  #  #  # ]:          0 :                         SPDK_DEBUGLOG(vfu_virtio_io, "%s: IRQ disabled\n",
     637                 :            :                                       spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint));
     638                 :          0 :                         return 0;
     639                 :            :                 }
     640                 :            : 
     641   [ #  #  #  # ]:          0 :                 SPDK_DEBUGLOG(vfu_virtio_io, "%s: Queue %u post ISR\n",
     642                 :            :                               spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint), vq->id);
     643                 :          0 :                 dev->cfg.isr = 1;
     644                 :          0 :                 return vfu_irq_trigger(vfu_ctx, 0);
     645                 :            :         }
     646                 :            : }
     647                 :            : 
     648                 :            : void
     649                 :   12154020 : vfu_virtio_vq_flush_irq(struct vfu_virtio_dev *dev, struct vfu_virtio_vq *vq)
     650                 :            : {
     651                 :   12154020 :         struct vfu_virtio_endpoint *virtio_endpoint = dev->virtio_endpoint;
     652                 :            :         uint32_t delay_us;
     653                 :            : 
     654         [ +  + ]:   12154020 :         if (vq->used_req_cnt == 0) {
     655                 :   10741548 :                 return;
     656                 :            :         }
     657                 :            : 
     658                 :            :         /* No need to notify client */
     659         [ +  + ]:    1412472 :         if (virtio_queue_event_is_suppressed(dev, vq)) {
     660                 :    1394703 :                 return;
     661                 :            :         }
     662                 :            : 
     663                 :            :         /* Interrupt coalescing disabled */
     664         [ +  - ]:      17769 :         if (!virtio_endpoint->coalescing_delay_us) {
     665                 :      17769 :                 vfu_virtio_vq_post_irq(dev, vq);
     666                 :      17769 :                 return;
     667                 :            :         }
     668                 :            : 
     669                 :            :         /* No need for event right now */
     670         [ #  # ]:          0 :         if (spdk_get_ticks() < vq->next_event_time) {
     671                 :          0 :                 return;
     672                 :            :         }
     673                 :            : 
     674                 :          0 :         vfu_virtio_vq_post_irq(dev, vq);
     675                 :            : 
     676                 :          0 :         delay_us = virtio_endpoint->coalescing_delay_us;
     677                 :          0 :         vq->next_event_time = spdk_get_ticks() + delay_us * spdk_get_ticks_hz() / (1000000ULL);
     678                 :            : }
     679                 :            : 
     680                 :            : int
     681                 :    2516589 : vfu_virtio_dev_process_split_ring(struct vfu_virtio_dev *dev, struct vfu_virtio_vq *vq)
     682                 :            : {
     683                 :    2516589 :         struct vfu_virtio_endpoint *virtio_endpoint = dev->virtio_endpoint;
     684                 :            :         struct vfu_virtio_req *req;
     685                 :    2516589 :         uint16_t reqs_idx[VIRTIO_DEV_VRING_MAX_REQS];
     686                 :            :         uint16_t reqs_cnt, i;
     687                 :            :         int ret;
     688                 :            : 
     689                 :    2516589 :         reqs_cnt = virtio_dev_split_get_avail_reqs(dev, vq, reqs_idx, VIRTIO_DEV_VRING_MAX_REQS);
     690         [ +  + ]:    2516589 :         if (!reqs_cnt) {
     691                 :    2442236 :                 return 0;
     692                 :            :         }
     693                 :            : 
     694   [ -  +  -  + ]:      74353 :         SPDK_DEBUGLOG(vfu_virtio_io, "%s: get %u descriptors\n", dev->name, reqs_cnt);
     695                 :            : 
     696         [ +  + ]:    2434820 :         for (i = 0; i < reqs_cnt; i++) {
     697                 :    2360467 :                 req = vfu_virtio_dev_get_req(virtio_endpoint, vq);
     698         [ -  + ]:    2360467 :                 if (spdk_unlikely(!req)) {
     699                 :          0 :                         SPDK_ERRLOG("Error to get request\n");
     700                 :            :                         /* TODO: address the error case */
     701                 :          0 :                         return -EIO;
     702                 :            :                 }
     703                 :            : 
     704                 :    2360467 :                 req->req_idx = reqs_idx[i];
     705                 :    2360467 :                 ret = virtio_dev_split_iovs_setup(dev, vq, req->req_idx, req);
     706         [ -  + ]:    2360467 :                 if (spdk_unlikely(ret)) {
     707                 :            :                         /* let the device to response this error */
     708                 :          0 :                         SPDK_ERRLOG("Split vring setup failed with index %u\n", i);
     709                 :            :                 }
     710                 :            : 
     711         [ -  + ]:    2360467 :                 assert(virtio_endpoint->virtio_ops.exec_request);
     712                 :    2360467 :                 virtio_endpoint->io_outstanding++;
     713                 :    2360467 :                 virtio_endpoint->virtio_ops.exec_request(virtio_endpoint, vq, req);
     714                 :            :         }
     715                 :            : 
     716                 :      74353 :         return i;
     717                 :            : }
     718                 :            : 
     719                 :            : struct vfu_virtio_req *
     720                 :          0 : virito_dev_split_ring_get_next_avail_req(struct vfu_virtio_dev *dev, struct vfu_virtio_vq *vq)
     721                 :            : {
     722                 :          0 :         struct vfu_virtio_endpoint *virtio_endpoint = dev->virtio_endpoint;
     723                 :            :         struct vfu_virtio_req *req;
     724                 :          0 :         uint16_t reqs_idx[VIRTIO_DEV_VRING_MAX_REQS];
     725                 :            :         uint16_t reqs_cnt;
     726                 :            :         int ret;
     727                 :            : 
     728                 :          0 :         reqs_cnt = virtio_dev_split_get_avail_reqs(dev, vq, reqs_idx, 1);
     729         [ #  # ]:          0 :         if (!reqs_cnt) {
     730                 :          0 :                 return NULL;
     731                 :            :         }
     732         [ #  # ]:          0 :         assert(reqs_cnt == 1);
     733                 :            : 
     734   [ #  #  #  # ]:          0 :         SPDK_DEBUGLOG(vfu_virtio_io, "%s: get 1 descriptors\n", dev->name);
     735                 :            : 
     736                 :          0 :         req = vfu_virtio_dev_get_req(virtio_endpoint, vq);
     737         [ #  # ]:          0 :         if (!req) {
     738                 :          0 :                 SPDK_ERRLOG("Error to get request\n");
     739                 :          0 :                 return NULL;
     740                 :            :         }
     741                 :            : 
     742                 :          0 :         req->req_idx = reqs_idx[0];
     743                 :          0 :         ret = virtio_dev_split_iovs_setup(dev, vq, req->req_idx, req);
     744         [ #  # ]:          0 :         if (ret) {
     745                 :          0 :                 SPDK_ERRLOG("Split vring setup failed\n");
     746                 :          0 :                 vfu_virtio_dev_put_req(req);
     747                 :          0 :                 return NULL;
     748                 :            :         }
     749                 :            : 
     750                 :          0 :         return req;
     751                 :            : }
     752                 :            : 
     753                 :            : static inline void *
     754                 :     307305 : virtio_vring_packed_desc_to_iov(struct vfu_virtio_dev *dev, struct vring_packed_desc *desc,
     755                 :            :                                 dma_sg_t *sg, struct iovec *iov)
     756                 :            : {
     757                 :     307305 :         struct vfu_virtio_endpoint *virtio_endpoint = dev->virtio_endpoint;
     758                 :            : 
     759                 :     307305 :         return spdk_vfu_map_one(virtio_endpoint->endpoint, desc->addr, desc->len,
     760                 :            :                                 sg, iov, PROT_READ | PROT_WRITE);
     761                 :            : }
     762                 :            : 
     763                 :            : static int
     764                 :      49850 : virtio_dev_packed_iovs_setup(struct vfu_virtio_dev *dev, struct vfu_virtio_vq *vq,
     765                 :            :                              uint16_t last_avail_idx,
     766                 :            :                              struct vring_packed_desc *current_desc, struct vfu_virtio_req *req)
     767                 :            : {
     768                 :      49850 :         struct vring_packed_desc *desc, *desc_table = NULL;
     769                 :      49850 :         uint16_t new_idx, num_descs, desc_table_size = 0;
     770                 :      49850 :         uint32_t len = 0;
     771                 :            : 
     772   [ -  +  -  + ]:      49850 :         SPDK_DEBUGLOG(vfu_virtio_io, "%s: last avail idx %u, req %p\n", dev->name, last_avail_idx, req);
     773                 :            : 
     774                 :      49850 :         desc = NULL;
     775                 :      49850 :         num_descs = 1;
     776         [ +  - ]:      49850 :         if (virtio_vring_packed_desc_is_indirect(current_desc)) {
     777                 :      49850 :                 req->buffer_id = current_desc->id;
     778                 :      49850 :                 desc_table = virtio_vring_packed_desc_to_iov(dev, current_desc, req->indirect_sg,
     779                 :            :                                 req->indirect_iov);
     780         [ -  + ]:      49850 :                 if (spdk_unlikely(desc_table == NULL)) {
     781                 :          0 :                         SPDK_ERRLOG("Map Indirect Desc to IOV failed\n");
     782                 :          0 :                         return -EINVAL;
     783                 :            :                 }
     784                 :      49850 :                 desc_table_size = current_desc->len / sizeof(struct vring_packed_desc);
     785                 :      49850 :                 desc = desc_table;
     786   [ -  +  -  + ]:      49850 :                 SPDK_DEBUGLOG(vfu_virtio_io, "%s: indirect desc %p, desc size %u, req %p\n",
     787                 :            :                               dev->name, desc_table, desc_table_size, req);
     788                 :            :         } else {
     789                 :          0 :                 desc = current_desc;
     790                 :            :         }
     791                 :            : 
     792         [ -  + ]:      49850 :         assert(req->iovcnt == 0);
     793                 :            :         /* Map descs to IOVs */
     794                 :      49850 :         new_idx = last_avail_idx;
     795                 :            :         while (1) {
     796         [ -  + ]:     257455 :                 assert(desc != NULL);
     797         [ -  + ]:     257455 :                 if (spdk_unlikely(req->iovcnt == VIRTIO_DEV_MAX_IOVS)) {
     798                 :          0 :                         SPDK_ERRLOG("Max IOVs in request reached (iovcnt = %d).\n", req->iovcnt);
     799                 :          0 :                         return -EINVAL;
     800                 :            :                 }
     801                 :            : 
     802         [ -  + ]:     257455 :                 if (spdk_unlikely(!virtio_vring_packed_desc_to_iov(dev, desc, virtio_req_to_sg_t(req, req->iovcnt),
     803                 :            :                                   &req->iovs[req->iovcnt]))) {
     804                 :          0 :                         SPDK_ERRLOG("Map Desc to IOV failed (iovcnt = %d).\n", req->iovcnt);
     805                 :          0 :                         return -EINVAL;
     806                 :            :                 }
     807                 :     257455 :                 req->desc_writeable[req->iovcnt] = false;
     808         [ +  + ]:     257455 :                 if (virtio_vring_packed_desc_is_wr(desc)) {
     809                 :     130260 :                         req->desc_writeable[req->iovcnt] = true;
     810                 :            :                 }
     811                 :            : 
     812                 :     257455 :                 req->iovcnt++;
     813                 :     257455 :                 len += desc->len;
     814                 :            : 
     815                 :            :                 /* get next desc */
     816         [ +  - ]:     257455 :                 if (desc_table) {
     817         [ +  + ]:     257455 :                         if (req->iovcnt < desc_table_size) {
     818                 :     207605 :                                 desc = &desc_table[req->iovcnt];
     819                 :            :                         } else {
     820                 :      49850 :                                 desc = NULL;
     821                 :            :                         }
     822                 :            :                 } else {
     823         [ #  # ]:          0 :                         if ((desc->flags & VRING_DESC_F_NEXT) == 0) {
     824                 :          0 :                                 req->buffer_id = desc->id;
     825                 :          0 :                                 desc = NULL;
     826                 :            :                         } else {
     827         [ #  # ]:          0 :                                 new_idx = (new_idx + 1) % vq->qsize;
     828                 :          0 :                                 desc = &vq->desc.desc_packed[new_idx];
     829                 :          0 :                                 num_descs++;
     830                 :          0 :                                 req->buffer_id = desc->id;
     831                 :            :                         }
     832                 :            :                 }
     833                 :            : 
     834         [ +  + ]:     257455 :                 if (desc == NULL) {
     835                 :      49850 :                         break;
     836                 :            :                 }
     837                 :            :         }
     838                 :            : 
     839                 :      49850 :         req->num_descs = num_descs;
     840         [ -  + ]:      49850 :         vq->last_avail_idx = (new_idx + 1) % vq->qsize;
     841         [ +  + ]:      49850 :         if (vq->last_avail_idx < last_avail_idx) {
     842                 :        132 :                 vq->packed.avail_phase = !vq->packed.avail_phase;
     843                 :            :         }
     844                 :            : 
     845                 :      49850 :         req->payload_size = len;
     846                 :            : 
     847   [ -  +  -  + ]:      49850 :         SPDK_DEBUGLOG(vfu_virtio_io, "%s: req %p, iovcnt %u, num_descs %u\n",
     848                 :            :                       dev->name, req, req->iovcnt, num_descs);
     849                 :      49850 :         return 0;
     850                 :            : }
     851                 :            : 
     852                 :            : int
     853                 :    9637431 : vfu_virtio_dev_process_packed_ring(struct vfu_virtio_dev *dev, struct vfu_virtio_vq *vq)
     854                 :            : {
     855                 :    9637431 :         struct vfu_virtio_endpoint *virtio_endpoint = dev->virtio_endpoint;
     856                 :            :         struct vring_packed_desc *desc;
     857                 :            :         int ret;
     858                 :            :         struct vfu_virtio_req *req;
     859                 :            :         uint16_t i, max_reqs;
     860                 :            : 
     861                 :    9637431 :         max_reqs = VIRTIO_DEV_VRING_MAX_REQS;
     862         [ +  + ]:    9687281 :         for (i = 0; i < max_reqs; i++) {
     863                 :    9685853 :                 desc = &vq->desc.desc_packed[vq->last_avail_idx];
     864         [ +  + ]:    9685853 :                 if (!virtio_vring_packed_is_avail(desc, vq->packed.avail_phase)) {
     865                 :    9636003 :                         return i;
     866                 :            :                 }
     867                 :            : 
     868                 :      49850 :                 req = vfu_virtio_dev_get_req(virtio_endpoint, vq);
     869         [ -  + ]:      49850 :                 if (spdk_unlikely(!req)) {
     870                 :          0 :                         SPDK_ERRLOG("Error to get request\n");
     871                 :            :                         /* TODO: address the error case */
     872                 :          0 :                         assert(false);
     873                 :            :                         return -EIO;
     874                 :            :                 }
     875                 :            : 
     876                 :      49850 :                 ret = virtio_dev_packed_iovs_setup(dev, vq, vq->last_avail_idx, desc, req);
     877         [ -  + ]:      49850 :                 if (spdk_unlikely(ret)) {
     878                 :            :                         /* let the device to response the error */
     879                 :          0 :                         SPDK_ERRLOG("virtio_dev_packed_iovs_setup failed\n");
     880                 :            :                 }
     881                 :            : 
     882         [ -  + ]:      49850 :                 assert(virtio_endpoint->virtio_ops.exec_request);
     883                 :      49850 :                 virtio_endpoint->io_outstanding++;
     884                 :      49850 :                 virtio_endpoint->virtio_ops.exec_request(virtio_endpoint, vq, req);
     885                 :            :         }
     886                 :            : 
     887                 :       1428 :         return i;
     888                 :            : }
     889                 :            : 
     890                 :            : struct vfu_virtio_req *
     891                 :          0 : virito_dev_packed_ring_get_next_avail_req(struct vfu_virtio_dev *dev, struct vfu_virtio_vq *vq)
     892                 :            : {
     893                 :          0 :         struct vfu_virtio_endpoint *virtio_endpoint = dev->virtio_endpoint;
     894                 :            :         struct vring_packed_desc *desc;
     895                 :            :         int ret;
     896                 :            :         struct vfu_virtio_req *req;
     897                 :            : 
     898                 :          0 :         desc = &vq->desc.desc_packed[vq->last_avail_idx];
     899         [ #  # ]:          0 :         if (!virtio_vring_packed_is_avail(desc, vq->packed.avail_phase)) {
     900                 :          0 :                 return NULL;
     901                 :            :         }
     902                 :            : 
     903   [ #  #  #  # ]:          0 :         SPDK_DEBUGLOG(vfu_virtio_io, "%s: get 1 descriptors\n", dev->name);
     904                 :            : 
     905                 :          0 :         req = vfu_virtio_dev_get_req(virtio_endpoint, vq);
     906         [ #  # ]:          0 :         if (!req) {
     907                 :          0 :                 SPDK_ERRLOG("Error to get request\n");
     908                 :          0 :                 return NULL;
     909                 :            :         }
     910                 :            : 
     911                 :          0 :         ret = virtio_dev_packed_iovs_setup(dev, vq, vq->last_avail_idx, desc, req);
     912         [ #  # ]:          0 :         if (ret) {
     913                 :          0 :                 SPDK_ERRLOG("virtio_dev_packed_iovs_setup failed\n");
     914                 :          0 :                 vfu_virtio_dev_put_req(req);
     915                 :          0 :                 return NULL;
     916                 :            :         }
     917                 :            : 
     918                 :          0 :         return req;
     919                 :            : }
     920                 :            : 
     921                 :            : static int
     922                 :        574 : virtio_vfu_pci_common_cfg(struct vfu_virtio_endpoint *virtio_endpoint, char *buf,
     923                 :            :                           size_t count, loff_t pos, bool is_write)
     924                 :            : {
     925                 :        574 :         struct vfu_virtio_dev *dev = virtio_endpoint->dev;
     926                 :        574 :         uint32_t offset, value = 0;
     927                 :            :         int ret;
     928                 :            : 
     929         [ -  + ]:        574 :         assert(count <= 4);
     930                 :        574 :         offset = pos - VIRTIO_PCI_COMMON_CFG_OFFSET;
     931                 :            : 
     932         [ +  + ]:        574 :         if (is_write) {
     933         [ -  + ]:        406 :                 memcpy(&value, buf, count);
     934   [ +  +  +  +  :        406 :                 switch (offset) {
          +  +  +  +  +  
          +  +  +  +  +  
                   +  - ]
     935                 :         20 :                 case VIRTIO_PCI_COMMON_DFSELECT:
     936                 :         20 :                         dev->cfg.host_feature_select = value;
     937   [ -  +  +  + ]:         20 :                         SPDK_DEBUGLOG(vfu_virtio, "%s: WRITE PCI_COMMON_DFSELECT with 0x%x\n",
     938                 :            :                                       spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint),
     939                 :            :                                       value);
     940                 :         20 :                         break;
     941                 :         20 :                 case VIRTIO_PCI_COMMON_GFSELECT:
     942                 :         20 :                         dev->cfg.guest_feature_select = value;
     943   [ -  +  +  + ]:         20 :                         SPDK_DEBUGLOG(vfu_virtio, "%s: WRITE PCI_COMMON_GFSELECT with 0x%x\n",
     944                 :            :                                       spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint),
     945                 :            :                                       value);
     946                 :         20 :                         break;
     947                 :         20 :                 case VIRTIO_PCI_COMMON_GF:
     948         [ -  + ]:         20 :                         assert(dev->cfg.guest_feature_select <= 1);
     949         [ +  + ]:         20 :                         if (dev->cfg.guest_feature_select) {
     950                 :         10 :                                 dev->cfg.guest_feat_hi = value;
     951   [ -  +  +  + ]:         10 :                                 SPDK_DEBUGLOG(vfu_virtio, "%s: WRITE PCI_COMMON_GF_HI with 0x%x\n",
     952                 :            :                                               spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint),
     953                 :            :                                               value);
     954                 :            :                         } else {
     955                 :         10 :                                 dev->cfg.guest_feat_lo = value;
     956   [ -  +  +  + ]:         10 :                                 SPDK_DEBUGLOG(vfu_virtio, "%s: WRITE PCI_COMMON_GF_LO with 0x%x\n",
     957                 :            :                                               spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint),
     958                 :            :                                               value);
     959                 :            :                         }
     960                 :            : 
     961                 :         20 :                         ret = virtio_dev_set_features(dev,
     962                 :         20 :                                                       (((uint64_t)dev->cfg.guest_feat_hi << 32) | dev->cfg.guest_feat_lo));
     963         [ -  + ]:         20 :                         if (ret) {
     964                 :          0 :                                 return ret;
     965                 :            :                         }
     966                 :         20 :                         break;
     967                 :          4 :                 case VIRTIO_PCI_COMMON_MSIX:
     968                 :          4 :                         dev->cfg.msix_config = value;
     969   [ -  +  -  + ]:          4 :                         SPDK_DEBUGLOG(vfu_virtio, "%s: WRITE PCI_COMMON_MSIX with 0x%x\n",
     970                 :            :                                       spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint),
     971                 :            :                                       value);
     972                 :          4 :                         break;
     973                 :         48 :                 case VIRTIO_PCI_COMMON_STATUS:
     974   [ -  +  +  + ]:         48 :                         SPDK_DEBUGLOG(vfu_virtio, "%s: WRITE PCI_COMMON_STATUS with 0x%x\n",
     975                 :            :                                       spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint),
     976                 :            :                                       value);
     977                 :         48 :                         ret = virtio_dev_set_status(dev, value);
     978         [ -  + ]:         48 :                         if (ret) {
     979                 :          0 :                                 return ret;
     980                 :            :                         }
     981                 :         48 :                         break;
     982                 :        106 :                 case VIRTIO_PCI_COMMON_Q_SELECT:
     983         [ +  - ]:        106 :                         if (value < VIRTIO_DEV_MAX_VQS) {
     984                 :        106 :                                 dev->cfg.queue_select = value;
     985                 :            :                         }
     986   [ -  +  +  + ]:        106 :                         SPDK_DEBUGLOG(vfu_virtio, "%s: WRITE PCI_COMMON_Q_SELECT with 0x%x\n",
     987                 :            :                                       spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint),
     988                 :            :                                       value);
     989                 :        106 :                         break;
     990                 :         16 :                 case VIRTIO_PCI_COMMON_Q_SIZE:
     991                 :         16 :                         dev->vqs[dev->cfg.queue_select].qsize = value;
     992   [ -  +  -  + ]:         16 :                         SPDK_DEBUGLOG(vfu_virtio, "%s: WRITE PCI_COMMON_Q_SIZE with 0x%x\n",
     993                 :            :                                       spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint),
     994                 :            :                                       value);
     995                 :         16 :                         break;
     996                 :         12 :                 case VIRTIO_PCI_COMMON_Q_MSIX:
     997                 :         12 :                         dev->vqs[dev->cfg.queue_select].vector = value;
     998   [ -  +  -  + ]:         12 :                         SPDK_DEBUGLOG(vfu_virtio, "%s: WRITE PCI_COMMON_Q_MSIX with 0x%x\n",
     999                 :            :                                       spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint),
    1000                 :            :                                       value);
    1001                 :         12 :                         break;
    1002                 :         28 :                 case VIRTIO_PCI_COMMON_Q_ENABLE:
    1003   [ -  +  +  + ]:         28 :                         SPDK_DEBUGLOG(vfu_virtio, "%s: WRITE PCI_COMMON_Q_ENABLE with 0x%x\n",
    1004                 :            :                                       spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint),
    1005                 :            :                                       value);
    1006         [ +  + ]:         28 :                         if (value == 1) {
    1007                 :         22 :                                 ret = virtio_dev_enable_vq(dev, dev->cfg.queue_select);
    1008         [ -  + ]:         22 :                                 if (ret) {
    1009                 :          0 :                                         return ret;
    1010                 :            :                                 }
    1011                 :            :                         } else {
    1012                 :          6 :                                 ret = virtio_dev_disable_vq(dev, dev->cfg.queue_select);
    1013         [ -  + ]:          6 :                                 if (ret) {
    1014                 :          0 :                                         return ret;
    1015                 :            :                                 }
    1016                 :            :                         }
    1017                 :         28 :                         break;
    1018                 :         22 :                 case VIRTIO_PCI_COMMON_Q_DESCLO:
    1019                 :         22 :                         dev->vqs[dev->cfg.queue_select].desc_lo = value;
    1020   [ -  +  +  + ]:         22 :                         SPDK_DEBUGLOG(vfu_virtio, "%s: WRITE queue %u PCI_COMMON_Q_DESCLO with 0x%x\n",
    1021                 :            :                                       spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint), dev->cfg.queue_select, value);
    1022                 :         22 :                         break;
    1023                 :         22 :                 case VIRTIO_PCI_COMMON_Q_DESCHI:
    1024                 :         22 :                         dev->vqs[dev->cfg.queue_select].desc_hi = value;
    1025   [ -  +  +  + ]:         22 :                         SPDK_DEBUGLOG(vfu_virtio, "%s: WRITE queue %u PCI_COMMON_Q_DESCHI with 0x%x\n",
    1026                 :            :                                       spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint), dev->cfg.queue_select, value);
    1027                 :         22 :                         break;
    1028                 :         22 :                 case VIRTIO_PCI_COMMON_Q_AVAILLO:
    1029                 :         22 :                         dev->vqs[dev->cfg.queue_select].avail_lo = value;
    1030   [ -  +  +  + ]:         22 :                         SPDK_DEBUGLOG(vfu_virtio, "%s: WRITE queue %u PCI_COMMON_Q_AVAILLO with 0x%x\n",
    1031                 :            :                                       spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint), dev->cfg.queue_select, value);
    1032                 :         22 :                         break;
    1033                 :         22 :                 case VIRTIO_PCI_COMMON_Q_AVAILHI:
    1034                 :         22 :                         dev->vqs[dev->cfg.queue_select].avail_hi = value;
    1035   [ -  +  +  + ]:         22 :                         SPDK_DEBUGLOG(vfu_virtio, "%s: WRITE queue %u PCI_COMMON_Q_AVAILHI with 0x%x\n",
    1036                 :            :                                       spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint), dev->cfg.queue_select, value);
    1037                 :         22 :                         break;
    1038                 :         22 :                 case VIRTIO_PCI_COMMON_Q_USEDLO:
    1039                 :         22 :                         dev->vqs[dev->cfg.queue_select].used_lo = value;
    1040   [ -  +  +  + ]:         22 :                         SPDK_DEBUGLOG(vfu_virtio, "%s: WRITE queue %u PCI_COMMON_Q_USEDLO with 0x%x\n",
    1041                 :            :                                       spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint), dev->cfg.queue_select, value);
    1042                 :         22 :                         break;
    1043                 :         22 :                 case VIRTIO_PCI_COMMON_Q_USEDHI:
    1044                 :         22 :                         dev->vqs[dev->cfg.queue_select].used_hi = value;
    1045   [ -  +  +  + ]:         22 :                         SPDK_DEBUGLOG(vfu_virtio, "%s: WRITE queue %u PCI_COMMON_Q_USEDHI with 0x%x\n",
    1046                 :            :                                       spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint), dev->cfg.queue_select, value);
    1047                 :         22 :                         break;
    1048                 :            : 
    1049                 :          0 :                 default:
    1050                 :          0 :                         SPDK_ERRLOG("%s: WRITE UNSUPPORTED offset 0x%x\n",
    1051                 :            :                                     spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint), offset);
    1052                 :          0 :                         errno = EIO;
    1053                 :          0 :                         return -1;
    1054                 :            :                 }
    1055                 :            :         } else {
    1056   [ -  +  -  -  :        168 :                 switch (offset) {
          +  +  +  +  +  
          -  +  +  +  -  
          -  -  -  -  -  
                      - ]
    1057                 :          0 :                 case VIRTIO_PCI_COMMON_DFSELECT:
    1058                 :          0 :                         value = dev->cfg.host_feature_select;
    1059   [ #  #  #  # ]:          0 :                         SPDK_DEBUGLOG(vfu_virtio, "%s: READ PCI_COMMON_DFSELECT with 0x%x\n",
    1060                 :            :                                       spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint),
    1061                 :            :                                       value);
    1062                 :          0 :                         break;
    1063                 :         20 :                 case VIRTIO_PCI_COMMON_DF:
    1064         [ -  + ]:         20 :                         assert(dev->cfg.host_feature_select <= 1);
    1065         [ +  + ]:         20 :                         if (dev->cfg.host_feature_select) {
    1066                 :         10 :                                 value = dev->host_features >> 32;
    1067   [ -  +  +  + ]:         10 :                                 SPDK_DEBUGLOG(vfu_virtio, "%s: READ PCI_COMMON_DF_HI with 0x%x\n",
    1068                 :            :                                               spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint),
    1069                 :            :                                               value);
    1070                 :            :                         } else {
    1071                 :         10 :                                 value = dev->host_features;
    1072   [ -  +  +  + ]:         10 :                                 SPDK_DEBUGLOG(vfu_virtio, "%s: READ PCI_COMMON_DF_LO with 0x%x\n",
    1073                 :            :                                               spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint),
    1074                 :            :                                               value);
    1075                 :            :                         }
    1076                 :         20 :                         break;
    1077                 :          0 :                 case VIRTIO_PCI_COMMON_GFSELECT:
    1078                 :          0 :                         value = dev->cfg.guest_feature_select;
    1079   [ #  #  #  # ]:          0 :                         SPDK_DEBUGLOG(vfu_virtio, "%s: READ PCI_COMMON_GFSELECT with 0x%x\n",
    1080                 :            :                                       spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint),
    1081                 :            :                                       value);
    1082                 :          0 :                         break;
    1083                 :          0 :                 case VIRTIO_PCI_COMMON_GF:
    1084         [ #  # ]:          0 :                         assert(dev->cfg.guest_feature_select <= 1);
    1085         [ #  # ]:          0 :                         if (dev->cfg.guest_feature_select) {
    1086                 :          0 :                                 value = dev->cfg.guest_feat_hi;
    1087   [ #  #  #  # ]:          0 :                                 SPDK_DEBUGLOG(vfu_virtio, "%s: READ PCI_COMMON_GF_HI with 0x%x\n",
    1088                 :            :                                               spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint),
    1089                 :            :                                               value);
    1090                 :            :                         } else {
    1091                 :          0 :                                 value = dev->cfg.guest_feat_lo;
    1092   [ #  #  #  # ]:          0 :                                 SPDK_DEBUGLOG(vfu_virtio, "%s: READ PCI_COMMON_GF_LO with 0x%x\n",
    1093                 :            :                                               spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint),
    1094                 :            :                                               value);
    1095                 :            :                         }
    1096                 :          0 :                         break;
    1097                 :          4 :                 case VIRTIO_PCI_COMMON_MSIX:
    1098                 :          4 :                         value = dev->cfg.msix_config;
    1099   [ -  +  -  + ]:          4 :                         SPDK_DEBUGLOG(vfu_virtio, "%s: READ PCI_COMMON_MSIX with 0x%x\n",
    1100                 :            :                                       spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint),
    1101                 :            :                                       value);
    1102                 :          4 :                         break;
    1103                 :         12 :                 case VIRTIO_PCI_COMMON_NUMQ:
    1104                 :         12 :                         value = dev->num_queues;
    1105   [ -  +  -  + ]:         12 :                         SPDK_DEBUGLOG(vfu_virtio, "%s: READ PCI_COMMON_NUMQ with 0x%x\n",
    1106                 :            :                                       spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint),
    1107                 :            :                                       value);
    1108                 :         12 :                         break;
    1109                 :         52 :                 case VIRTIO_PCI_COMMON_STATUS:
    1110                 :         52 :                         value = dev->cfg.device_status;
    1111   [ -  +  +  + ]:         52 :                         SPDK_DEBUGLOG(vfu_virtio, "%s: READ PCI_COMMON_STATUS with 0x%x\n",
    1112                 :            :                                       spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint),
    1113                 :            :                                       value);
    1114                 :         52 :                         break;
    1115                 :          4 :                 case VIRTIO_PCI_COMMON_CFGGENERATION:
    1116                 :          4 :                         value = dev->cfg.config_generation;
    1117   [ -  +  -  + ]:          4 :                         SPDK_DEBUGLOG(vfu_virtio, "%s: READ PCI_COMMON_CFGGENERATION with 0x%x\n",
    1118                 :            :                                       spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint),
    1119                 :            :                                       value);
    1120                 :          4 :                         break;
    1121                 :         22 :                 case VIRTIO_PCI_COMMON_Q_NOFF:
    1122                 :         22 :                         value = dev->cfg.queue_select;
    1123   [ -  +  +  + ]:         22 :                         SPDK_DEBUGLOG(vfu_virtio, "%s: READ PCI_COMMON_Q_NOFF with 0x%x\n",
    1124                 :            :                                       spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint),
    1125                 :            :                                       value);
    1126                 :         22 :                         break;
    1127                 :          0 :                 case VIRTIO_PCI_COMMON_Q_SELECT:
    1128                 :          0 :                         value = dev->cfg.queue_select;
    1129   [ #  #  #  # ]:          0 :                         SPDK_DEBUGLOG(vfu_virtio, "%s: READ PCI_COMMON_Q_SELECT with 0x%x\n",
    1130                 :            :                                       spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint),
    1131                 :            :                                       value);
    1132                 :          0 :                         break;
    1133                 :         26 :                 case VIRTIO_PCI_COMMON_Q_SIZE:
    1134                 :         26 :                         value = dev->vqs[dev->cfg.queue_select].qsize;
    1135   [ -  +  +  + ]:         26 :                         SPDK_DEBUGLOG(vfu_virtio, "%s: READ queue %u PCI_COMMON_Q_SIZE with 0x%x\n",
    1136                 :            :                                       spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint),
    1137                 :            :                                       dev->cfg.queue_select, value);
    1138                 :         26 :                         break;
    1139                 :         12 :                 case VIRTIO_PCI_COMMON_Q_MSIX:
    1140                 :         12 :                         value = dev->vqs[dev->cfg.queue_select].vector;
    1141   [ -  +  -  + ]:         12 :                         SPDK_DEBUGLOG(vfu_virtio, "%s: READ queue %u PCI_COMMON_Q_MSIX with 0x%x\n",
    1142                 :            :                                       spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint),
    1143                 :            :                                       dev->cfg.queue_select, value);
    1144                 :         12 :                         break;
    1145                 :         16 :                 case VIRTIO_PCI_COMMON_Q_ENABLE:
    1146         [ -  + ]:         16 :                         value = dev->vqs[dev->cfg.queue_select].enabled;
    1147   [ -  +  -  + ]:         16 :                         SPDK_DEBUGLOG(vfu_virtio, "%s: READ queue %u PCI_COMMON_Q_ENABLE with 0x%x\n",
    1148                 :            :                                       spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint), dev->cfg.queue_select, value);
    1149                 :         16 :                         break;
    1150                 :          0 :                 case VIRTIO_PCI_COMMON_Q_DESCLO:
    1151                 :          0 :                         value = dev->vqs[dev->cfg.queue_select].desc_lo;
    1152   [ #  #  #  # ]:          0 :                         SPDK_DEBUGLOG(vfu_virtio, "%s: READ queue %u PCI_COMMON_Q_DESCLO with 0x%x\n",
    1153                 :            :                                       spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint), dev->cfg.queue_select, value);
    1154                 :          0 :                         break;
    1155                 :          0 :                 case VIRTIO_PCI_COMMON_Q_DESCHI:
    1156                 :          0 :                         value = dev->vqs[dev->cfg.queue_select].desc_hi;
    1157   [ #  #  #  # ]:          0 :                         SPDK_DEBUGLOG(vfu_virtio, "%s: READ queue %u PCI_COMMON_Q_DESCHI with 0x%x\n",
    1158                 :            :                                       spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint), dev->cfg.queue_select, value);
    1159                 :          0 :                         break;
    1160                 :          0 :                 case VIRTIO_PCI_COMMON_Q_AVAILLO:
    1161                 :          0 :                         value = dev->vqs[dev->cfg.queue_select].avail_lo;
    1162   [ #  #  #  # ]:          0 :                         SPDK_DEBUGLOG(vfu_virtio, "%s: READ queue %u PCI_COMMON_Q_AVAILLO with 0x%x\n",
    1163                 :            :                                       spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint), dev->cfg.queue_select, value);
    1164                 :          0 :                         break;
    1165                 :          0 :                 case VIRTIO_PCI_COMMON_Q_AVAILHI:
    1166                 :          0 :                         value = dev->vqs[dev->cfg.queue_select].avail_hi;
    1167   [ #  #  #  # ]:          0 :                         SPDK_DEBUGLOG(vfu_virtio, "%s: READ queue %u PCI_COMMON_Q_AVAILHI with 0x%x\n",
    1168                 :            :                                       spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint), dev->cfg.queue_select, value);
    1169                 :          0 :                         break;
    1170                 :          0 :                 case VIRTIO_PCI_COMMON_Q_USEDLO:
    1171                 :          0 :                         value = dev->vqs[dev->cfg.queue_select].used_lo;
    1172   [ #  #  #  # ]:          0 :                         SPDK_DEBUGLOG(vfu_virtio, "%s: READ queue %u PCI_COMMON_Q_USEDLO with 0x%x\n",
    1173                 :            :                                       spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint), dev->cfg.queue_select, value);
    1174                 :          0 :                         break;
    1175                 :          0 :                 case VIRTIO_PCI_COMMON_Q_USEDHI:
    1176                 :          0 :                         value = dev->vqs[dev->cfg.queue_select].used_hi;
    1177   [ #  #  #  # ]:          0 :                         SPDK_DEBUGLOG(vfu_virtio, "%s: READ queue %u PCI_COMMON_Q_USEDHI with 0x%x\n",
    1178                 :            :                                       spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint), dev->cfg.queue_select, value);
    1179                 :          0 :                         break;
    1180                 :          0 :                 default:
    1181                 :          0 :                         SPDK_ERRLOG("%s: READ UNSUPPORTED offset 0x%x\n",
    1182                 :            :                                     spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint), offset);
    1183                 :          0 :                         errno = EIO;
    1184                 :          0 :                         return -1;
    1185                 :            :                 }
    1186         [ -  + ]:        168 :                 memcpy(buf, &value, count);
    1187                 :            :         }
    1188                 :            : 
    1189                 :        574 :         return count;
    1190                 :            : }
    1191                 :            : 
    1192                 :            : static int
    1193                 :         67 : virtio_vfu_device_specific_cfg(struct vfu_virtio_endpoint *virtio_endpoint, char *buf,
    1194                 :            :                                size_t count, loff_t pos, bool is_write)
    1195                 :            : {
    1196                 :            :         loff_t offset;
    1197                 :         67 :         int ret = -1;
    1198                 :            : 
    1199         [ -  + ]:         67 :         assert(count <= 8);
    1200                 :         67 :         offset = pos - VIRTIO_PCI_SPECIFIC_CFG_OFFSET;
    1201         [ +  + ]:         67 :         if (!is_write) {
    1202         [ +  - ]:         63 :                 if (virtio_endpoint->virtio_ops.get_config) {
    1203                 :         63 :                         ret = virtio_endpoint->virtio_ops.get_config(virtio_endpoint, buf, offset, count);
    1204                 :            :                 }
    1205                 :            :         } else {
    1206         [ +  - ]:          4 :                 if (virtio_endpoint->virtio_ops.set_config) {
    1207                 :          4 :                         ret = virtio_endpoint->virtio_ops.set_config(virtio_endpoint, buf, offset, count);
    1208                 :            :                 }
    1209                 :            :         }
    1210                 :            : 
    1211         [ -  + ]:         67 :         if (ret < 0) {
    1212                 :          0 :                 return ret;
    1213                 :            :         }
    1214                 :            : 
    1215                 :         67 :         return count;
    1216                 :            : }
    1217                 :            : 
    1218                 :            : static int
    1219                 :        526 : virtio_vfu_pci_isr(struct vfu_virtio_endpoint *virtio_endpoint, char *buf,
    1220                 :            :                    size_t count, bool is_write)
    1221                 :            : {
    1222                 :            :         uint8_t *isr;
    1223                 :            : 
    1224         [ -  + ]:        526 :         if (count != 1) {
    1225                 :          0 :                 SPDK_ERRLOG("ISR register is 1 byte\n");
    1226                 :          0 :                 errno = EIO;
    1227                 :          0 :                 return -1;
    1228                 :            :         }
    1229                 :            : 
    1230                 :        526 :         isr = buf;
    1231                 :            : 
    1232         [ +  - ]:        526 :         if (!is_write) {
    1233   [ -  +  -  + ]:        526 :                 SPDK_DEBUGLOG(vfu_virtio, "READ PCI ISR\n");
    1234                 :            :                 /* Read-Acknowledge Clear */
    1235                 :        526 :                 *isr = virtio_endpoint->dev->cfg.isr;
    1236                 :        526 :                 virtio_endpoint->dev->cfg.isr = 0;
    1237                 :            :         } else {
    1238                 :          0 :                 SPDK_ERRLOG("ISR register is RO\n");
    1239                 :          0 :                 errno = EIO;
    1240                 :          0 :                 return -1;
    1241                 :            :         }
    1242                 :            : 
    1243                 :        526 :         return count;
    1244                 :            : }
    1245                 :            : 
    1246                 :            : static ssize_t
    1247                 :       1167 : virtio_vfu_access_bar4(vfu_ctx_t *vfu_ctx, char *buf, size_t count,
    1248                 :            :                        loff_t pos,
    1249                 :            :                        bool is_write)
    1250                 :            : {
    1251                 :       1167 :         struct spdk_vfu_endpoint *endpoint = vfu_get_private(vfu_ctx);
    1252                 :       1167 :         struct vfu_virtio_endpoint *virtio_endpoint = spdk_vfu_get_endpoint_private(endpoint);
    1253                 :            :         uint64_t start, end;
    1254                 :            : 
    1255                 :       1167 :         start = pos;
    1256                 :       1167 :         end = start + count;
    1257   [ -  +  +  +  :       1167 :         SPDK_DEBUGLOG(vfu_virtio, "%s: %s bar4 0x%"PRIX64"-0x%"PRIX64", len = %lu\n",
                   +  + ]
    1258                 :            :                       spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint),
    1259                 :            :                       is_write ? "write" : "read", start, end - 1, count);
    1260                 :            : 
    1261         [ +  + ]:       1167 :         if (end < VIRTIO_PCI_COMMON_CFG_OFFSET + VIRTIO_PCI_COMMON_CFG_LENGTH) {
    1262                 :            :                 /* virtio PCI common configuration */
    1263                 :        574 :                 return virtio_vfu_pci_common_cfg(virtio_endpoint, buf, count, pos, is_write);
    1264   [ +  -  +  + ]:        593 :         } else if (start >= VIRTIO_PCI_ISR_ACCESS_OFFSET &&
    1265                 :            :                    end < VIRTIO_PCI_ISR_ACCESS_OFFSET + VIRTIO_PCI_ISR_ACCESS_LENGTH) {
    1266                 :            :                 /* ISR access */
    1267                 :        526 :                 return virtio_vfu_pci_isr(virtio_endpoint, buf, count, is_write);
    1268   [ +  -  +  - ]:         67 :         } else if (start >= VIRTIO_PCI_SPECIFIC_CFG_OFFSET &&
    1269                 :            :                    end < VIRTIO_PCI_SPECIFIC_CFG_OFFSET + VIRTIO_PCI_SPECIFIC_CFG_LENGTH) {
    1270                 :            :                 /* Device specific configuration */
    1271                 :         67 :                 return virtio_vfu_device_specific_cfg(virtio_endpoint, buf, count, pos, is_write);
    1272   [ #  #  #  # ]:          0 :         } else if (start >= VIRTIO_PCI_NOTIFICATIONS_OFFSET &&
    1273                 :            :                    end < VIRTIO_PCI_NOTIFICATIONS_OFFSET + VIRTIO_PCI_NOTIFICATIONS_LENGTH) {
    1274                 :            :                 /* Notifications */
    1275                 :            :                 /* Sparse mmap region by default, there are no MMIO R/W messages */
    1276                 :          0 :                 assert(false);
    1277                 :            :                 return count;
    1278                 :            :         } else {
    1279                 :          0 :                 assert(false);
    1280                 :            :         }
    1281                 :            : 
    1282                 :            :         return 0;
    1283                 :            : }
    1284                 :            : 
    1285                 :            : int
    1286                 :         66 : vfu_virtio_post_memory_add(struct spdk_vfu_endpoint *endpoint, void *map_start, void *map_end)
    1287                 :            : {
    1288                 :         66 :         struct vfu_virtio_endpoint *virtio_endpoint = spdk_vfu_get_endpoint_private(endpoint);
    1289                 :         66 :         struct vfu_virtio_dev *dev = virtio_endpoint->dev;
    1290                 :            :         uint32_t i;
    1291                 :            : 
    1292         [ -  + ]:         66 :         if (!dev) {
    1293                 :          0 :                 return 0;
    1294                 :            :         }
    1295                 :            : 
    1296         [ +  + ]:        264 :         for (i = 0; i < dev->num_queues; i++) {
    1297                 :            :                 /* Try to remap VQs if necessary */
    1298                 :        198 :                 virtio_dev_map_vq(dev, &dev->vqs[i]);
    1299                 :            :         }
    1300                 :            : 
    1301                 :         66 :         return 0;
    1302                 :            : }
    1303                 :            : 
    1304                 :            : int
    1305                 :         66 : vfu_virtio_pre_memory_remove(struct spdk_vfu_endpoint *endpoint, void *map_start, void *map_end)
    1306                 :            : {
    1307                 :         66 :         struct vfu_virtio_endpoint *virtio_endpoint = spdk_vfu_get_endpoint_private(endpoint);
    1308                 :            : 
    1309         [ +  - ]:         66 :         if (virtio_endpoint->dev != NULL) {
    1310                 :         66 :                 vfu_virtio_dev_unmap_vqs(virtio_endpoint->dev, map_start, map_end);
    1311                 :            :         }
    1312                 :            : 
    1313                 :         66 :         return 0;
    1314                 :            : }
    1315                 :            : 
    1316                 :            : int
    1317                 :         14 : vfu_virtio_pci_reset_cb(struct spdk_vfu_endpoint *endpoint)
    1318                 :            : {
    1319                 :         14 :         struct vfu_virtio_endpoint *virtio_endpoint = spdk_vfu_get_endpoint_private(endpoint);
    1320                 :            : 
    1321         [ +  + ]:         14 :         if (virtio_endpoint->dev) {
    1322                 :         10 :                 vfu_virtio_dev_stop(virtio_endpoint->dev);
    1323                 :         10 :                 vfu_virtio_dev_reset(virtio_endpoint->dev);
    1324                 :            :         }
    1325                 :            : 
    1326                 :         14 :         return 0;
    1327                 :            : }
    1328                 :            : 
    1329                 :            : static ssize_t
    1330                 :          0 : access_pci_config(vfu_ctx_t *vfu_ctx, char *buf, size_t count, loff_t offset,
    1331                 :            :                   bool is_write)
    1332                 :            : {
    1333                 :          0 :         struct spdk_vfu_endpoint *endpoint = vfu_get_private(vfu_ctx);
    1334                 :          0 :         void *pci_config = spdk_vfu_endpoint_get_pci_config(endpoint);
    1335                 :            : 
    1336   [ #  #  #  #  :          0 :         SPDK_DEBUGLOG(vfu_virtio,
                   #  # ]
    1337                 :            :                       "%s: PCI_CFG %s %#lx-%#lx\n",
    1338                 :            :                       spdk_vfu_get_endpoint_id(endpoint), is_write ? "write" : "read",
    1339                 :            :                       offset, offset + count);
    1340                 :            : 
    1341         [ #  # ]:          0 :         if (is_write) {
    1342                 :          0 :                 SPDK_ERRLOG("write %#lx-%#lx not supported\n",
    1343                 :            :                             offset, offset + count);
    1344                 :          0 :                 errno = EINVAL;
    1345                 :          0 :                 return -1;
    1346                 :            :         }
    1347                 :            : 
    1348         [ #  # ]:          0 :         if (offset + count > 0x1000) {
    1349                 :          0 :                 SPDK_ERRLOG("access past end of extended PCI configuration space, want=%ld+%ld, max=%d\n",
    1350                 :            :                             offset, count, 0x1000);
    1351                 :          0 :                 errno = ERANGE;
    1352                 :          0 :                 return -1;
    1353                 :            :         }
    1354                 :            : 
    1355   [ #  #  #  # ]:          0 :         memcpy(buf, ((unsigned char *)pci_config) + offset, count);
    1356                 :          0 :         return count;
    1357                 :            : }
    1358                 :            : 
    1359                 :            : static int
    1360                 :         10 : vfu_virtio_dev_start(struct vfu_virtio_dev *dev)
    1361                 :            : {
    1362                 :         10 :         struct vfu_virtio_endpoint *virtio_endpoint = dev->virtio_endpoint;
    1363                 :         10 :         int ret = 0;
    1364                 :            : 
    1365   [ -  +  +  + ]:         10 :         SPDK_DEBUGLOG(vfu_virtio, "start %s\n", dev->name);
    1366                 :            : 
    1367         [ -  + ]:         10 :         if (virtio_dev_is_started(dev)) {
    1368                 :          0 :                 SPDK_ERRLOG("Device %s is already started\n", dev->name);
    1369                 :          0 :                 return -EFAULT;
    1370                 :            :         }
    1371                 :            : 
    1372         [ +  - ]:         10 :         if (virtio_endpoint->virtio_ops.start_device) {
    1373                 :         10 :                 virtio_endpoint->io_outstanding = 0;
    1374                 :         10 :                 ret = virtio_endpoint->virtio_ops.start_device(virtio_endpoint);
    1375                 :            :         }
    1376                 :            : 
    1377   [ -  +  +  + ]:         10 :         SPDK_DEBUGLOG(vfu_virtio, "%s is started with ret %d\n", dev->name, ret);
    1378                 :            : 
    1379                 :         10 :         return ret;
    1380                 :            : }
    1381                 :            : 
    1382                 :            : static int
    1383                 :         22 : vfu_virtio_dev_stop(struct vfu_virtio_dev *dev)
    1384                 :            : {
    1385                 :         22 :         struct vfu_virtio_endpoint *virtio_endpoint = dev->virtio_endpoint;
    1386                 :         22 :         int ret = 0;
    1387                 :            : 
    1388   [ -  +  +  + ]:         22 :         SPDK_DEBUGLOG(vfu_virtio, "stop %s\n", dev->name);
    1389                 :            : 
    1390         [ +  + ]:         22 :         if (!virtio_dev_is_started(dev)) {
    1391   [ -  +  +  + ]:         12 :                 SPDK_DEBUGLOG(vfu_virtio, "%s isn't started\n", dev->name);
    1392                 :         12 :                 return 0;
    1393                 :            :         }
    1394                 :            : 
    1395         [ +  - ]:         10 :         if (virtio_endpoint->virtio_ops.stop_device) {
    1396                 :         10 :                 ret = virtio_endpoint->virtio_ops.stop_device(virtio_endpoint);
    1397         [ -  + ]:         10 :                 assert(ret == 0);
    1398                 :            :         }
    1399                 :            : 
    1400                 :            :         /* Unmap all VQs */
    1401                 :         10 :         vfu_virtio_dev_unmap_vqs(dev, NULL, NULL);
    1402                 :            : 
    1403                 :         10 :         return ret;
    1404                 :            : }
    1405                 :            : 
    1406                 :            : int
    1407                 :         10 : vfu_virtio_detach_device(struct spdk_vfu_endpoint *endpoint)
    1408                 :            : {
    1409                 :         10 :         struct vfu_virtio_endpoint *virtio_endpoint = spdk_vfu_get_endpoint_private(endpoint);
    1410                 :         10 :         struct vfu_virtio_dev *dev = virtio_endpoint->dev;
    1411                 :            : 
    1412         [ +  + ]:         10 :         if (virtio_endpoint->dev == NULL) {
    1413                 :          4 :                 return 0;
    1414                 :            :         }
    1415                 :            : 
    1416   [ -  +  +  + ]:          6 :         SPDK_DEBUGLOG(vfu_virtio, "detach device %s\n", dev->name);
    1417                 :            : 
    1418                 :          6 :         vfu_virtio_dev_stop(dev);
    1419                 :          6 :         vfu_virtio_dev_free_reqs(virtio_endpoint, dev);
    1420                 :          6 :         virtio_endpoint->dev = NULL;
    1421                 :          6 :         free(dev);
    1422                 :            : 
    1423                 :          6 :         return 0;
    1424                 :            : }
    1425                 :            : 
    1426                 :            : int
    1427                 :          6 : vfu_virtio_attach_device(struct spdk_vfu_endpoint *endpoint)
    1428                 :            : {
    1429                 :          6 :         struct vfu_virtio_endpoint *virtio_endpoint = spdk_vfu_get_endpoint_private(endpoint);
    1430                 :          6 :         uint64_t supported_features = 0;
    1431                 :            :         struct vfu_virtio_dev *dev;
    1432                 :            :         struct vfu_virtio_vq *vq;
    1433                 :            :         struct vfu_virtio_req *req;
    1434                 :            :         uint32_t i, j;
    1435                 :          6 :         int ret = 0;
    1436                 :            : 
    1437                 :          6 :         dev = calloc(1, sizeof(*dev) + virtio_endpoint->num_queues * 3 * dma_sg_size());
    1438         [ -  + ]:          6 :         if (dev == NULL) {
    1439                 :          0 :                 return -ENOMEM;
    1440                 :            :         }
    1441                 :            : 
    1442                 :          6 :         dev->num_queues = virtio_endpoint->num_queues;
    1443         [ +  + ]:         24 :         for (i = 0; i < dev->num_queues; i++) {
    1444                 :         18 :                 vq = &dev->vqs[i];
    1445                 :         18 :                 vq->id = i;
    1446                 :         18 :                 vq->qsize = virtio_endpoint->qsize;
    1447                 :         18 :                 vq->avail.sg = (dma_sg_t *)(dev->sg + i * dma_sg_size() * 3);
    1448                 :         18 :                 vq->used.sg = (dma_sg_t *)((uint8_t *)vq->avail.sg + dma_sg_size());
    1449                 :         18 :                 vq->desc.sg = (dma_sg_t *)((uint8_t *)vq->used.sg + dma_sg_size());
    1450                 :            : 
    1451                 :         18 :                 STAILQ_INIT(&vq->free_reqs);
    1452         [ +  + ]:       7716 :                 for (j = 0; j <= vq->qsize; j++) {
    1453                 :       7698 :                         req = vfu_virtio_vq_alloc_req(virtio_endpoint, vq);
    1454         [ -  + ]:       7698 :                         if (!req) {
    1455                 :          0 :                                 SPDK_ERRLOG("Error to allocate req\n");
    1456                 :          0 :                                 ret = -ENOMEM;
    1457                 :          0 :                                 goto out;
    1458                 :            :                         }
    1459                 :       7698 :                         req->indirect_iov = &req->iovs[VIRTIO_DEV_MAX_IOVS];
    1460                 :       7698 :                         req->indirect_sg = virtio_req_to_sg_t(req, VIRTIO_DEV_MAX_IOVS);
    1461                 :       7698 :                         req->dev = dev;
    1462                 :       7698 :                         req->vq = vq;
    1463                 :       7698 :                         STAILQ_INSERT_TAIL(&vq->free_reqs, req, link);
    1464                 :            :                 }
    1465                 :            :         }
    1466                 :            : 
    1467         [ +  - ]:          6 :         if (virtio_endpoint->virtio_ops.get_device_features) {
    1468                 :          6 :                 supported_features = virtio_endpoint->virtio_ops.get_device_features(virtio_endpoint);
    1469                 :            :         }
    1470                 :          6 :         dev->host_features = supported_features;
    1471                 :            : 
    1472         [ -  + ]:          6 :         snprintf(dev->name, SPDK_VFU_MAX_NAME_LEN, "%s",
    1473                 :            :                  spdk_vfu_get_endpoint_name(virtio_endpoint->endpoint));
    1474                 :          6 :         virtio_endpoint->dev = dev;
    1475                 :          6 :         dev->virtio_endpoint = virtio_endpoint;
    1476                 :          6 :         virtio_endpoint->thread = spdk_get_thread();
    1477                 :          6 :         return 0;
    1478                 :            : 
    1479                 :          0 : out:
    1480                 :          0 :         vfu_virtio_dev_free_reqs(virtio_endpoint, dev);
    1481                 :          0 :         return ret;
    1482                 :            : }
    1483                 :            : 
    1484                 :            : int
    1485                 :          4 : vfu_virtio_endpoint_setup(struct vfu_virtio_endpoint *virtio_endpoint,
    1486                 :            :                           struct spdk_vfu_endpoint *endpoint,
    1487                 :            :                           char *basename, const char *endpoint_name,
    1488                 :            :                           struct vfu_virtio_ops *ops)
    1489                 :            : {
    1490                 :          4 :         char path[PATH_MAX] = "";
    1491                 :            :         int ret;
    1492                 :            : 
    1493         [ -  + ]:          4 :         if (!ops) {
    1494                 :          0 :                 return -EINVAL;
    1495                 :            :         }
    1496                 :            : 
    1497                 :          4 :         ret = snprintf(path, PATH_MAX, "%s%s_bar4", basename, endpoint_name);
    1498   [ +  -  -  + ]:          4 :         if (ret < 0 || ret >= PATH_MAX) {
    1499                 :          0 :                 SPDK_ERRLOG("%s: error to get socket path: %s.\n", basename, spdk_strerror(errno));
    1500                 :          0 :                 return -EINVAL;
    1501                 :            :         }
    1502                 :            : 
    1503                 :          4 :         ret = open(path, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
    1504         [ -  + ]:          4 :         if (ret == -1) {
    1505                 :          0 :                 SPDK_ERRLOG("%s: failed to open device memory at %s.\n",
    1506                 :            :                             path, spdk_strerror(errno));
    1507                 :          0 :                 return ret;
    1508                 :            :         }
    1509                 :          4 :         unlink(path);
    1510                 :            : 
    1511                 :          4 :         virtio_endpoint->devmem_fd = ret;
    1512                 :          4 :         ret = ftruncate(virtio_endpoint->devmem_fd, VIRTIO_PCI_BAR4_LENGTH);
    1513         [ -  + ]:          4 :         if (ret != 0) {
    1514                 :          0 :                 SPDK_ERRLOG("%s: error to ftruncate file %s.\n", path,
    1515                 :            :                             spdk_strerror(errno));
    1516                 :          0 :                 close(virtio_endpoint->devmem_fd);
    1517                 :          0 :                 return ret;
    1518                 :            :         }
    1519                 :            : 
    1520                 :          4 :         virtio_endpoint->doorbells = mmap(NULL, VIRTIO_PCI_NOTIFICATIONS_LENGTH, PROT_READ | PROT_WRITE,
    1521                 :            :                                           MAP_SHARED,
    1522                 :            :                                           virtio_endpoint->devmem_fd, VIRTIO_PCI_NOTIFICATIONS_OFFSET);
    1523         [ -  + ]:          4 :         if (virtio_endpoint->doorbells == MAP_FAILED) {
    1524                 :          0 :                 SPDK_ERRLOG("%s: error to mmap file %s.\n", path, spdk_strerror(errno));
    1525                 :          0 :                 close(virtio_endpoint->devmem_fd);
    1526                 :          0 :                 return -EFAULT;
    1527                 :            :         }
    1528                 :          4 :         virtio_endpoint->endpoint = endpoint;
    1529                 :          4 :         virtio_endpoint->virtio_ops = *ops;
    1530                 :          4 :         virtio_endpoint->num_queues = VIRTIO_DEV_MAX_VQS;
    1531                 :          4 :         virtio_endpoint->qsize = VIRTIO_VQ_DEFAULT_SIZE;
    1532                 :            : 
    1533   [ -  +  +  + ]:          4 :         SPDK_DEBUGLOG(vfu_virtio, "mmap file %s, devmem_fd %d\n", path, virtio_endpoint->devmem_fd);
    1534                 :          4 :         return 0;
    1535                 :            : }
    1536                 :            : 
    1537                 :            : int
    1538                 :          4 : vfu_virtio_endpoint_destruct(struct vfu_virtio_endpoint *virtio_endpoint)
    1539                 :            : {
    1540         [ +  - ]:          4 :         if (virtio_endpoint->doorbells) {
    1541                 :          4 :                 munmap((void *)virtio_endpoint->doorbells, VIRTIO_PCI_NOTIFICATIONS_LENGTH);
    1542                 :            :         }
    1543                 :            : 
    1544         [ +  - ]:          4 :         if (virtio_endpoint->devmem_fd) {
    1545                 :          4 :                 close(virtio_endpoint->devmem_fd);
    1546                 :            :         }
    1547                 :            : 
    1548                 :          4 :         return 0;
    1549                 :            : }
    1550                 :            : 
    1551                 :            : static int
    1552                 :          0 : vfu_virtio_quiesce_poll(void *ctx)
    1553                 :            : {
    1554                 :          0 :         struct vfu_virtio_endpoint *virtio_endpoint = ctx;
    1555                 :          0 :         vfu_ctx_t *vfu_ctx = spdk_vfu_get_vfu_ctx(virtio_endpoint->endpoint);
    1556                 :            : 
    1557         [ #  # ]:          0 :         if (virtio_endpoint->io_outstanding) {
    1558                 :          0 :                 return SPDK_POLLER_IDLE;
    1559                 :            :         }
    1560                 :            : 
    1561                 :          0 :         spdk_poller_unregister(&virtio_endpoint->quiesce_poller);
    1562                 :          0 :         virtio_endpoint->quiesce_in_progress = false;
    1563                 :          0 :         vfu_device_quiesced(vfu_ctx, 0);
    1564                 :            : 
    1565                 :          0 :         return SPDK_POLLER_BUSY;
    1566                 :            : }
    1567                 :            : 
    1568                 :            : int
    1569                 :        290 : vfu_virtio_quiesce_cb(struct spdk_vfu_endpoint *endpoint)
    1570                 :            : {
    1571                 :        290 :         struct vfu_virtio_endpoint *virtio_endpoint = spdk_vfu_get_endpoint_private(endpoint);
    1572                 :            : 
    1573   [ -  +  -  + ]:        290 :         if (virtio_endpoint->quiesce_in_progress) {
    1574                 :          0 :                 return -EBUSY;
    1575                 :            :         }
    1576                 :            : 
    1577         [ +  - ]:        290 :         if (!virtio_endpoint->io_outstanding) {
    1578                 :        290 :                 return 0;
    1579                 :            :         }
    1580                 :            : 
    1581                 :          0 :         virtio_endpoint->quiesce_in_progress = true;
    1582                 :          0 :         virtio_endpoint->quiesce_poller = SPDK_POLLER_REGISTER(vfu_virtio_quiesce_poll, virtio_endpoint,
    1583                 :            :                                           10);
    1584                 :            : 
    1585                 :          0 :         return -EBUSY;
    1586                 :            : }
    1587                 :            : 
    1588                 :            : static struct spdk_vfu_pci_device vfu_virtio_device_info = {
    1589                 :            :         .id = {
    1590                 :            :                 .vid = SPDK_PCI_VID_VIRTIO,
    1591                 :            :                 /* Realize when calling get device information */
    1592                 :            :                 .did = 0x0,
    1593                 :            :                 .ssvid = SPDK_PCI_VID_VIRTIO,
    1594                 :            :                 .ssid = 0x0,
    1595                 :            :         },
    1596                 :            : 
    1597                 :            :         .class = {
    1598                 :            :                 /* 0x01, mass storage controller */
    1599                 :            :                 .bcc = 0x01,
    1600                 :            :                 /* 0x00, SCSI controller */
    1601                 :            :                 .scc = 0x00,
    1602                 :            :                 /* 0x00, SCSI controller - vendor specific interface */
    1603                 :            :                 .pi = 0x00,
    1604                 :            :         },
    1605                 :            : 
    1606                 :            :         .pmcap = {
    1607                 :            :                 .hdr.id = PCI_CAP_ID_PM,
    1608                 :            :                 .pmcs.nsfrst = 0x1,
    1609                 :            :         },
    1610                 :            : 
    1611                 :            :         .pxcap = {
    1612                 :            :                 .hdr.id = PCI_CAP_ID_EXP,
    1613                 :            :                 .pxcaps.ver = 0x2,
    1614                 :            :                 .pxdcap = {.rer = 0x1, .flrc = 0x1},
    1615                 :            :                 .pxdcap2.ctds = 0x1,
    1616                 :            :         },
    1617                 :            : 
    1618                 :            :         .msixcap = {
    1619                 :            :                 .hdr.id = PCI_CAP_ID_MSIX,
    1620                 :            :                 .mxc.ts = VIRTIO_DEV_MAX_VQS - 1,
    1621                 :            :                 .mtab = {.tbir = 0x1, .to = 0x0},
    1622                 :            :                 .mpba = {.pbir = 0x2, .pbao = 0x0},
    1623                 :            :         },
    1624                 :            : 
    1625                 :            :         .nr_vendor_caps = 4,
    1626                 :            : 
    1627                 :            :         .intr_ipin = 0x1,
    1628                 :            :         .nr_int_irqs = 0x1,
    1629                 :            :         .nr_msix_irqs = VIRTIO_DEV_MAX_VQS,
    1630                 :            : 
    1631                 :            :         .regions = {
    1632                 :            :                 /* BAR0 */
    1633                 :            :                 {0},
    1634                 :            :                 /* BAR1 */
    1635                 :            :                 {
    1636                 :            :                         .access_cb = NULL,
    1637                 :            :                         .offset = 0,
    1638                 :            :                         .fd = -1,
    1639                 :            :                         .len = 0x1000,
    1640                 :            :                         .flags = VFU_REGION_FLAG_RW,
    1641                 :            :                         .nr_sparse_mmaps = 0,
    1642                 :            :                 },
    1643                 :            :                 /* BAR2 */
    1644                 :            :                 {
    1645                 :            :                         .access_cb = NULL,
    1646                 :            :                         .offset = 0,
    1647                 :            :                         .fd = -1,
    1648                 :            :                         .len = 0x1000,
    1649                 :            :                         .flags = VFU_REGION_FLAG_RW,
    1650                 :            :                         .nr_sparse_mmaps = 0,
    1651                 :            :                 },
    1652                 :            :                 /* BAR3 */
    1653                 :            :                 {0},
    1654                 :            :                 /* BAR4 */
    1655                 :            :                 {
    1656                 :            :                         .access_cb = virtio_vfu_access_bar4,
    1657                 :            :                         .offset = 0,
    1658                 :            :                         .fd = -1,
    1659                 :            :                         .len = VIRTIO_PCI_BAR4_LENGTH,
    1660                 :            :                         .flags = VFU_REGION_FLAG_RW | VFU_REGION_FLAG_MEM,
    1661                 :            :                         .nr_sparse_mmaps = 1,
    1662                 :            :                         .mmaps = {
    1663                 :            :                                 {
    1664                 :            :                                         .offset = VIRTIO_PCI_NOTIFICATIONS_OFFSET,
    1665                 :            :                                         .len = VIRTIO_PCI_NOTIFICATIONS_LENGTH,
    1666                 :            :                                 },
    1667                 :            :                         },
    1668                 :            :                 },
    1669                 :            :                 /* BAR5 */
    1670                 :            :                 {0},
    1671                 :            :                 /* BAR6 */
    1672                 :            :                 {0},
    1673                 :            :                 /* ROM */
    1674                 :            :                 {0},
    1675                 :            :                 /* PCI Config */
    1676                 :            :                 {
    1677                 :            :                         .access_cb = access_pci_config,
    1678                 :            :                         .offset = 0,
    1679                 :            :                         .fd = -1,
    1680                 :            :                         .len = 0x1000,
    1681                 :            :                         .flags = VFU_REGION_FLAG_RW,
    1682                 :            :                         .nr_sparse_mmaps = 0,
    1683                 :            :                 },
    1684                 :            :         },
    1685                 :            : };
    1686                 :            : 
    1687                 :            : void
    1688                 :          4 : vfu_virtio_get_device_info(struct vfu_virtio_endpoint *virtio_endpoint,
    1689                 :            :                            struct spdk_vfu_pci_device *device_info)
    1690                 :            : {
    1691   [ -  +  -  + ]:          4 :         memcpy(device_info, &vfu_virtio_device_info, sizeof(*device_info));
    1692                 :            : 
    1693                 :            :         /* BAR4 Region FD */
    1694                 :          4 :         device_info->regions[VFU_PCI_DEV_BAR4_REGION_IDX].fd = virtio_endpoint->devmem_fd;
    1695   [ -  +  +  + ]:          4 :         SPDK_DEBUGLOG(vfu_virtio, "%s: get device information, fd %d\n",
    1696                 :            :                       spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint),
    1697                 :            :                       virtio_endpoint->devmem_fd);
    1698                 :          4 : }
    1699                 :            : 
    1700                 :            : static struct virtio_pci_cap common_cap = {
    1701                 :            :         .cap_vndr = PCI_CAP_ID_VNDR,
    1702                 :            :         .cap_len = sizeof(common_cap),
    1703                 :            :         .cfg_type = VIRTIO_PCI_CAP_COMMON_CFG,
    1704                 :            :         .bar = 4,
    1705                 :            :         .offset = VIRTIO_PCI_COMMON_CFG_OFFSET,
    1706                 :            :         .length = VIRTIO_PCI_COMMON_CFG_LENGTH,
    1707                 :            : };
    1708                 :            : 
    1709                 :            : static struct virtio_pci_cap isr_cap = {
    1710                 :            :         .cap_vndr = PCI_CAP_ID_VNDR,
    1711                 :            :         .cap_len = sizeof(isr_cap),
    1712                 :            :         .cfg_type = VIRTIO_PCI_CAP_ISR_CFG,
    1713                 :            :         .bar = 4,
    1714                 :            :         .offset = VIRTIO_PCI_ISR_ACCESS_OFFSET,
    1715                 :            :         .length = VIRTIO_PCI_ISR_ACCESS_LENGTH,
    1716                 :            : };
    1717                 :            : 
    1718                 :            : static struct virtio_pci_cap dev_cap = {
    1719                 :            :         .cap_vndr = PCI_CAP_ID_VNDR,
    1720                 :            :         .cap_len = sizeof(dev_cap),
    1721                 :            :         .cfg_type = VIRTIO_PCI_CAP_DEVICE_CFG,
    1722                 :            :         .bar = 4,
    1723                 :            :         .offset = VIRTIO_PCI_SPECIFIC_CFG_OFFSET,
    1724                 :            :         .length = VIRTIO_PCI_SPECIFIC_CFG_LENGTH,
    1725                 :            : };
    1726                 :            : 
    1727                 :            : static struct virtio_pci_notify_cap notify_cap = {
    1728                 :            :         .cap = {
    1729                 :            :                 .cap_vndr = PCI_CAP_ID_VNDR,
    1730                 :            :                 .cap_len = sizeof(notify_cap),
    1731                 :            :                 .cfg_type = VIRTIO_PCI_CAP_NOTIFY_CFG,
    1732                 :            :                 .bar = 4,
    1733                 :            :                 .offset = VIRTIO_PCI_NOTIFICATIONS_OFFSET,
    1734                 :            :                 .length = VIRTIO_PCI_NOTIFICATIONS_LENGTH,
    1735                 :            :         },
    1736                 :            :         .notify_off_multiplier = 4,
    1737                 :            : };
    1738                 :            : 
    1739                 :            : uint16_t
    1740                 :         16 : vfu_virtio_get_vendor_capability(struct spdk_vfu_endpoint *endpoint, char *buf,
    1741                 :            :                                  uint16_t buf_len,
    1742                 :            :                                  uint16_t idx)
    1743                 :            : {
    1744                 :            :         uint16_t len;
    1745                 :            : 
    1746   [ -  +  +  + ]:         16 :         SPDK_DEBUGLOG(vfu_virtio, "%s: get vendor capability, idx %u\n",
    1747                 :            :                       spdk_vfu_get_endpoint_id(endpoint), idx);
    1748                 :            : 
    1749   [ +  +  +  +  :         16 :         switch (idx) {
                      - ]
    1750                 :          4 :         case 0:
    1751         [ -  + ]:          4 :                 assert(buf_len > sizeof(common_cap));
    1752                 :          4 :                 memcpy(buf, &common_cap, sizeof(common_cap));
    1753                 :          4 :                 len = sizeof(common_cap);
    1754                 :          4 :                 break;
    1755                 :          4 :         case 1:
    1756         [ -  + ]:          4 :                 assert(buf_len > sizeof(isr_cap));
    1757                 :          4 :                 memcpy(buf, &isr_cap, sizeof(isr_cap));
    1758                 :          4 :                 len = sizeof(isr_cap);
    1759                 :          4 :                 break;
    1760                 :          4 :         case 2:
    1761         [ -  + ]:          4 :                 assert(buf_len > sizeof(dev_cap));
    1762                 :          4 :                 memcpy(buf, &dev_cap, sizeof(dev_cap));
    1763                 :          4 :                 len = sizeof(dev_cap);
    1764                 :          4 :                 break;
    1765                 :          4 :         case 3:
    1766         [ -  + ]:          4 :                 assert(buf_len > sizeof(notify_cap));
    1767   [ -  +  -  + ]:          4 :                 memcpy(buf, &notify_cap, sizeof(notify_cap));
    1768                 :          4 :                 len = sizeof(notify_cap);
    1769                 :          4 :                 break;
    1770                 :          0 :         default:
    1771                 :          0 :                 return 0;
    1772                 :            :         }
    1773                 :            : 
    1774                 :         16 :         return len;
    1775                 :            : }
    1776                 :            : 
    1777                 :        198 : SPDK_LOG_REGISTER_COMPONENT(vfu_virtio)
    1778                 :        198 : SPDK_LOG_REGISTER_COMPONENT(vfu_virtio_io)

Generated by: LCOV version 1.14