LCOV - code coverage report
Current view: top level - spdk/lib/vfu_tgt - tgt_endpoint.c (source / functions) Hit Total Coverage
Test: Combined Lines: 343 493 69.6 %
Date: 2024-12-10 00:23:43 Functions: 30 33 90.9 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 250 1538 16.3 %

           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                 :            : #include "spdk/stdinc.h"
       7                 :            : #include "spdk/env.h"
       8                 :            : #include "spdk/thread.h"
       9                 :            : #include "spdk/log.h"
      10                 :            : #include "spdk/util.h"
      11                 :            : #include "spdk/memory.h"
      12                 :            : #include "spdk/cpuset.h"
      13                 :            : #include "spdk/likely.h"
      14                 :            : #include "spdk/vfu_target.h"
      15                 :            : 
      16                 :            : #include "tgt_internal.h"
      17                 :            : 
      18                 :            : struct tgt_pci_device_ops {
      19                 :            :         struct spdk_vfu_endpoint_ops ops;
      20                 :            :         TAILQ_ENTRY(tgt_pci_device_ops) link;
      21                 :            : };
      22                 :            : 
      23                 :            : static struct spdk_cpuset g_tgt_core_mask;
      24                 :            : static pthread_mutex_t g_endpoint_lock = PTHREAD_MUTEX_INITIALIZER;
      25                 :            : static TAILQ_HEAD(, spdk_vfu_endpoint) g_endpoint = TAILQ_HEAD_INITIALIZER(g_endpoint);
      26                 :            : static TAILQ_HEAD(, tgt_pci_device_ops) g_pci_device_ops = TAILQ_HEAD_INITIALIZER(g_pci_device_ops);
      27                 :            : static char g_endpoint_path_dirname[PATH_MAX] = "";
      28                 :            : static uint32_t g_fini_endpoint_cnt = 0;
      29                 :            : static spdk_vfu_fini_cb g_fini_cb = NULL;
      30                 :            : 
      31                 :            : static struct spdk_vfu_endpoint_ops *
      32                 :        848 : tgt_get_pci_device_ops(const char *device_type_name)
      33                 :            : {
      34                 :            :         struct tgt_pci_device_ops *pci_ops, *tmp;
      35                 :        848 :         bool exist = false;
      36                 :            : 
      37         [ +  - ]:        848 :         pthread_mutex_lock(&g_endpoint_lock);
      38   [ +  +  +  -  :       1695 :         TAILQ_FOREACH_SAFE(pci_ops, &g_pci_device_ops, link, tmp) {
          +  -  +  -  +  
                      + ]
      39   [ +  +  +  +  :        852 :                 if (!strncmp(device_type_name, pci_ops->ops.name, SPDK_VFU_MAX_NAME_LEN)) {
          +  +  +  -  +  
                      - ]
      40                 :          5 :                         exist = true;
      41                 :          5 :                         break;
      42                 :            :                 }
      43                 :        174 :         }
      44         [ +  - ]:        848 :         pthread_mutex_unlock(&g_endpoint_lock);
      45                 :            : 
      46   [ +  +  -  + ]:        848 :         if (exist) {
      47         [ #  # ]:          5 :                 return &pci_ops->ops;
      48                 :            :         }
      49                 :        843 :         return NULL;
      50                 :        174 : }
      51                 :            : 
      52                 :            : int
      53                 :        843 : spdk_vfu_register_endpoint_ops(struct spdk_vfu_endpoint_ops *ops)
      54                 :            : {
      55                 :            :         struct tgt_pci_device_ops *pci_ops;
      56                 :            :         struct spdk_vfu_endpoint_ops *tmp;
      57                 :            : 
      58         [ +  - ]:        843 :         tmp = tgt_get_pci_device_ops(ops->name);
      59         [ -  + ]:        843 :         if (tmp) {
      60                 :          0 :                 return -EEXIST;
      61                 :            :         }
      62                 :            : 
      63                 :        843 :         pci_ops = calloc(1, sizeof(*pci_ops));
      64         [ +  + ]:        843 :         if (!pci_ops) {
      65                 :          0 :                 return -ENOMEM;
      66                 :            :         }
      67         [ -  + ]:        843 :         pci_ops->ops = *ops;
      68                 :            : 
      69         [ -  + ]:        843 :         pthread_mutex_lock(&g_endpoint_lock);
      70   [ -  +  -  +  :        843 :         TAILQ_INSERT_TAIL(&g_pci_device_ops, pci_ops, link);
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
             +  -  +  -  
                      + ]
      71         [ -  + ]:        843 :         pthread_mutex_unlock(&g_endpoint_lock);
      72                 :            : 
      73                 :        843 :         return 0;
      74                 :        174 : }
      75                 :            : 
      76                 :            : static char *
      77                 :          5 : tgt_get_base_path(void)
      78                 :            : {
      79                 :          5 :         return g_endpoint_path_dirname;
      80                 :            : }
      81                 :            : 
      82                 :            : int
      83                 :          4 : spdk_vfu_set_socket_path(const char *basename)
      84                 :            : {
      85                 :            :         int ret;
      86                 :            : 
      87   [ +  -  +  -  :          4 :         if (basename && strlen(basename) > 0) {
                   #  # ]
      88         [ -  + ]:          4 :                 ret = snprintf(g_endpoint_path_dirname, sizeof(g_endpoint_path_dirname) - 2, "%s", basename);
      89         [ -  + ]:          4 :                 if (ret <= 0) {
      90                 :          0 :                         return -EINVAL;
      91                 :            :                 }
      92         [ -  + ]:          4 :                 if ((size_t)ret >= sizeof(g_endpoint_path_dirname) - 2) {
      93                 :          0 :                         SPDK_ERRLOG("Char dev dir path length %d is too long\n", ret);
      94                 :          0 :                         return -EINVAL;
      95                 :            :                 }
      96                 :            : 
      97   [ +  -  #  #  :          4 :                 if (g_endpoint_path_dirname[ret - 1] != '/') {
          #  #  #  #  #  
                      # ]
      98   [ #  #  #  #  :          4 :                         g_endpoint_path_dirname[ret] = '/';
                   #  # ]
      99   [ #  #  #  #  :          4 :                         g_endpoint_path_dirname[ret + 1]  = '\0';
             #  #  #  # ]
     100                 :          0 :                 }
     101                 :          0 :         }
     102                 :            : 
     103                 :          4 :         return 0;
     104                 :          0 : }
     105                 :            : 
     106                 :            : struct spdk_vfu_endpoint *
     107                 :         15 : spdk_vfu_get_endpoint_by_name(const char *name)
     108                 :            : {
     109                 :            :         struct spdk_vfu_endpoint *endpoint, *tmp;
     110                 :         15 :         bool exist = false;
     111                 :            : 
     112         [ #  # ]:         15 :         pthread_mutex_lock(&g_endpoint_lock);
     113   [ +  +  #  #  :         19 :         TAILQ_FOREACH_SAFE(endpoint, &g_endpoint, link, tmp) {
          #  #  #  #  #  
                      # ]
     114   [ -  +  -  +  :         14 :                 if (!strncmp(name, endpoint->name, SPDK_VFU_MAX_NAME_LEN)) {
             +  +  #  # ]
     115                 :         10 :                         exist = true;
     116                 :         10 :                         break;
     117                 :            :                 }
     118                 :          0 :         }
     119         [ #  # ]:         15 :         pthread_mutex_unlock(&g_endpoint_lock);
     120                 :            : 
     121   [ +  +  #  # ]:         15 :         if (exist) {
     122                 :         10 :                 return endpoint;
     123                 :            :         }
     124                 :          5 :         return NULL;
     125                 :          0 : }
     126                 :            : 
     127                 :            : static int
     128                 :     215706 : tgt_vfu_ctx_poller(void *ctx)
     129                 :            : {
     130                 :     215706 :         struct spdk_vfu_endpoint *endpoint = ctx;
     131   [ #  #  #  # ]:     215706 :         vfu_ctx_t *vfu_ctx = endpoint->vfu_ctx;
     132                 :            :         int ret;
     133                 :            : 
     134                 :     215706 :         ret = vfu_run_ctx(vfu_ctx);
     135         [ +  + ]:     215706 :         if (spdk_unlikely(ret == -1)) {
     136   [ -  +  #  # ]:          7 :                 if (errno == EBUSY) {
     137                 :          0 :                         return SPDK_POLLER_IDLE;
     138                 :            :                 }
     139                 :            : 
     140   [ +  -  #  # ]:          7 :                 if (errno == ENOTCONN) {
     141         [ #  # ]:          7 :                         spdk_poller_unregister(&endpoint->vfu_ctx_poller);
     142   [ +  -  #  #  :          7 :                         if (endpoint->ops.detach_device) {
             #  #  #  # ]
     143   [ #  #  #  #  :          7 :                                 endpoint->ops.detach_device(endpoint);
          #  #  #  #  #  
                      # ]
     144                 :          0 :                         }
     145   [ #  #  #  # ]:          7 :                         endpoint->is_attached = false;
     146                 :          7 :                         return SPDK_POLLER_BUSY;
     147                 :            :                 }
     148                 :          0 :         }
     149                 :            : 
     150                 :     215699 :         return ret != 0 ? SPDK_POLLER_BUSY : SPDK_POLLER_IDLE;
     151                 :          0 : }
     152                 :            : 
     153                 :            : static int
     154                 :     243207 : tgt_accept_poller(void *ctx)
     155                 :            : {
     156                 :     243207 :         struct spdk_vfu_endpoint *endpoint = ctx;
     157                 :            :         int ret;
     158                 :            : 
     159   [ -  +  +  +  :     243207 :         if (endpoint->is_attached) {
             #  #  #  # ]
     160                 :     215706 :                 return SPDK_POLLER_IDLE;
     161                 :            :         }
     162                 :            : 
     163   [ #  #  #  # ]:      27501 :         ret = vfu_attach_ctx(endpoint->vfu_ctx);
     164         [ +  + ]:      27501 :         if (ret == 0) {
     165   [ #  #  #  #  :          7 :                 ret = endpoint->ops.attach_device(endpoint);
          #  #  #  #  #  
                      # ]
     166         [ +  - ]:          7 :                 if (!ret) {
     167                 :          7 :                         SPDK_NOTICELOG("%s: attached successfully\n", spdk_vfu_get_endpoint_id(endpoint));
     168                 :            :                         /* Polling socket too frequently will cause performance issue */
     169   [ #  #  #  # ]:          7 :                         endpoint->vfu_ctx_poller = SPDK_POLLER_REGISTER(tgt_vfu_ctx_poller, endpoint, 1000);
     170   [ #  #  #  # ]:          7 :                         endpoint->is_attached = true;
     171                 :          0 :                 }
     172                 :          7 :                 return SPDK_POLLER_BUSY;
     173                 :            :         }
     174                 :            : 
     175   [ -  +  -  -  :      27494 :         if (errno == EAGAIN || errno == EWOULDBLOCK) {
             #  #  #  # ]
     176                 :      27494 :                 return SPDK_POLLER_IDLE;
     177                 :            :         }
     178                 :            : 
     179                 :          0 :         return SPDK_POLLER_BUSY;
     180                 :          0 : }
     181                 :            : 
     182                 :            : static void
     183                 :          0 : tgt_log_cb(vfu_ctx_t *vfu_ctx, int level, char const *msg)
     184                 :            : {
     185                 :          0 :         struct spdk_vfu_endpoint *endpoint = vfu_get_private(vfu_ctx);
     186                 :            : 
     187         [ #  # ]:          0 :         if (level >= LOG_DEBUG) {
     188   [ #  #  #  #  :          0 :                 SPDK_DEBUGLOG(vfu, "%s: %s\n", spdk_vfu_get_endpoint_id(endpoint), msg);
                   #  # ]
     189         [ #  # ]:          0 :         } else if (level >= LOG_INFO) {
     190   [ #  #  #  #  :          0 :                 SPDK_INFOLOG(vfu, "%s: %s\n", spdk_vfu_get_endpoint_id(endpoint), msg);
                   #  # ]
     191         [ #  # ]:          0 :         } else if (level >= LOG_NOTICE) {
     192                 :          0 :                 SPDK_NOTICELOG("%s: %s\n", spdk_vfu_get_endpoint_id(endpoint), msg);
     193         [ #  # ]:          0 :         } else if (level >= LOG_WARNING) {
     194                 :          0 :                 SPDK_WARNLOG("%s: %s\n", spdk_vfu_get_endpoint_id(endpoint), msg);
     195                 :          0 :         } else {
     196                 :          0 :                 SPDK_ERRLOG("%s: %s\n", spdk_vfu_get_endpoint_id(endpoint), msg);
     197                 :            :         }
     198                 :          0 : }
     199                 :            : 
     200                 :            : static int
     201                 :          5 : tgt_get_log_level(void)
     202                 :            : {
     203                 :            :         int level;
     204                 :            : 
     205         [ -  + ]:          5 :         if (SPDK_DEBUGLOG_FLAG_ENABLED("vfu")) {
     206                 :          0 :                 return LOG_DEBUG;
     207                 :            :         }
     208                 :            : 
     209                 :          5 :         level = spdk_log_to_syslog_level(spdk_log_get_level());
     210         [ -  + ]:          5 :         if (level < 0) {
     211                 :          0 :                 return LOG_ERR;
     212                 :            :         }
     213                 :            : 
     214                 :          5 :         return level;
     215                 :          0 : }
     216                 :            : 
     217                 :            : static void
     218                 :          5 : init_pci_config_space(vfu_pci_config_space_t *p, uint16_t ipin)
     219                 :            : {
     220                 :            :         /* MLBAR */
     221   [ #  #  #  #  :          5 :         p->hdr.bars[0].raw = 0x0;
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
     222                 :            :         /* MUBAR */
     223   [ #  #  #  #  :          5 :         p->hdr.bars[1].raw = 0x0;
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
     224                 :            : 
     225                 :            :         /* vendor specific, let's set them to zero for now */
     226   [ #  #  #  #  :          5 :         p->hdr.bars[3].raw = 0x0;
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
     227   [ #  #  #  #  :          5 :         p->hdr.bars[4].raw = 0x0;
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
     228   [ #  #  #  #  :          5 :         p->hdr.bars[5].raw = 0x0;
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
     229                 :            : 
     230                 :            :         /* enable INTx */
     231   [ #  #  #  #  :          5 :         p->hdr.intr.ipin = ipin;
          #  #  #  #  #  
             #  #  #  #  
                      # ]
     232                 :          5 : }
     233                 :            : 
     234                 :            : static void
     235                 :        202 : tgt_memory_region_add_cb(vfu_ctx_t *vfu_ctx, vfu_dma_info_t *info)
     236                 :            : {
     237                 :        202 :         struct spdk_vfu_endpoint *endpoint = vfu_get_private(vfu_ctx);
     238                 :            :         void *map_start, *map_end;
     239                 :            :         int ret;
     240                 :            : 
     241   [ +  +  #  #  :        202 :         if (!info->vaddr) {
                   #  # ]
     242                 :        120 :                 return;
     243                 :            :         }
     244                 :            : 
     245   [ #  #  #  #  :         82 :         map_start = info->mapping.iov_base;
                   #  # ]
     246   [ #  #  #  #  :         82 :         map_end = info->mapping.iov_base + info->mapping.iov_len;
          #  #  #  #  #  
                #  #  # ]
     247                 :            : 
     248   [ +  -  #  #  :         82 :         if (((uintptr_t)info->mapping.iov_base & MASK_2MB) ||
          #  #  #  #  #  
                #  #  # ]
     249   [ -  +  #  #  :         82 :             (info->mapping.iov_len & MASK_2MB)) {
             #  #  #  # ]
     250   [ #  #  #  #  :          0 :                 SPDK_DEBUGLOG(vfu, "Invalid memory region vaddr %p, IOVA %p-%p\n",
          #  #  #  #  #  
                      # ]
     251                 :            :                               info->vaddr, map_start, map_end);
     252                 :          0 :                 return;
     253                 :            :         }
     254                 :            : 
     255   [ +  +  #  #  :         82 :         if (info->prot == (PROT_WRITE | PROT_READ)) {
                   #  # ]
     256   [ #  #  #  #  :         62 :                 ret = spdk_mem_register(info->mapping.iov_base, info->mapping.iov_len);
          #  #  #  #  #  
                #  #  # ]
     257         [ -  + ]:         62 :                 if (ret) {
     258                 :          0 :                         SPDK_ERRLOG("Memory region register %p-%p failed, ret=%d\n",
     259                 :            :                                     map_start, map_end, ret);
     260                 :          0 :                 }
     261                 :          0 :         }
     262                 :            : 
     263   [ +  -  #  #  :         82 :         if (endpoint->ops.post_memory_add) {
             #  #  #  # ]
     264   [ #  #  #  #  :         82 :                 endpoint->ops.post_memory_add(endpoint, map_start, map_end);
          #  #  #  #  #  
                      # ]
     265                 :          0 :         }
     266                 :          0 : }
     267                 :            : 
     268                 :            : static void
     269                 :        202 : tgt_memory_region_remove_cb(vfu_ctx_t *vfu_ctx, vfu_dma_info_t *info)
     270                 :            : {
     271                 :        202 :         struct spdk_vfu_endpoint *endpoint = vfu_get_private(vfu_ctx);
     272                 :            :         void *map_start, *map_end;
     273                 :        202 :         int ret = 0;
     274                 :            : 
     275   [ +  +  #  #  :        202 :         if (!info->vaddr) {
                   #  # ]
     276                 :        120 :                 return;
     277                 :            :         }
     278                 :            : 
     279   [ #  #  #  #  :         82 :         map_start = info->mapping.iov_base;
                   #  # ]
     280   [ #  #  #  #  :         82 :         map_end = info->mapping.iov_base + info->mapping.iov_len;
          #  #  #  #  #  
                #  #  # ]
     281                 :            : 
     282   [ +  -  #  #  :         82 :         if (((uintptr_t)info->mapping.iov_base & MASK_2MB) ||
          #  #  #  #  #  
                #  #  # ]
     283   [ -  +  #  #  :         82 :             (info->mapping.iov_len & MASK_2MB)) {
             #  #  #  # ]
     284   [ #  #  #  #  :          0 :                 SPDK_DEBUGLOG(vfu, "Invalid memory region vaddr %p, IOVA %p-%p\n",
          #  #  #  #  #  
                      # ]
     285                 :            :                               info->vaddr, map_start, map_end);
     286                 :          0 :                 return;
     287                 :            :         }
     288                 :            : 
     289   [ +  -  #  #  :         82 :         if (endpoint->ops.pre_memory_remove) {
             #  #  #  # ]
     290   [ #  #  #  #  :         82 :                 endpoint->ops.pre_memory_remove(endpoint, map_start, map_end);
          #  #  #  #  #  
                      # ]
     291                 :          0 :         }
     292                 :            : 
     293   [ +  +  #  #  :         82 :         if (info->prot == (PROT_WRITE | PROT_READ)) {
                   #  # ]
     294   [ #  #  #  #  :         62 :                 ret = spdk_mem_unregister(info->mapping.iov_base, info->mapping.iov_len);
          #  #  #  #  #  
                #  #  # ]
     295         [ -  + ]:         62 :                 if (ret) {
     296                 :          0 :                         SPDK_ERRLOG("Memory region unregister %p-%p failed, ret=%d\n",
     297                 :            :                                     map_start, map_end, ret);
     298                 :          0 :                 }
     299                 :          0 :         }
     300                 :          0 : }
     301                 :            : 
     302                 :            : static int
     303                 :        361 : tgt_device_quiesce_cb(vfu_ctx_t *vfu_ctx)
     304                 :            : {
     305                 :        361 :         struct spdk_vfu_endpoint *endpoint = vfu_get_private(vfu_ctx);
     306                 :            :         int ret;
     307                 :            : 
     308   [ -  +  #  #  :        361 :         assert(endpoint->ops.quiesce_device);
          #  #  #  #  #  
                      # ]
     309   [ #  #  #  #  :        361 :         ret = endpoint->ops.quiesce_device(endpoint);
          #  #  #  #  #  
                      # ]
     310         [ -  + ]:        361 :         if (ret) {
     311         [ #  # ]:          0 :                 errno = EBUSY;
     312                 :          0 :                 ret = -1;
     313                 :          0 :         }
     314                 :            : 
     315                 :        361 :         return ret;
     316                 :            : }
     317                 :            : 
     318                 :            : static int
     319                 :         17 : tgt_device_reset_cb(vfu_ctx_t *vfu_ctx, vfu_reset_type_t type)
     320                 :            : {
     321                 :         17 :         struct spdk_vfu_endpoint *endpoint = vfu_get_private(vfu_ctx);
     322                 :            : 
     323   [ -  +  -  +  :         17 :         SPDK_DEBUGLOG(vfu, "Device reset type %u\n", type);
                   #  # ]
     324                 :            : 
     325   [ -  +  #  #  :         17 :         assert(endpoint->ops.reset_device);
          #  #  #  #  #  
                      # ]
     326   [ #  #  #  #  :         17 :         return endpoint->ops.reset_device(endpoint);
          #  #  #  #  #  
                      # ]
     327                 :            : }
     328                 :            : 
     329                 :            : static int
     330                 :          5 : tgt_endpoint_realize(struct spdk_vfu_endpoint *endpoint)
     331                 :            : {
     332                 :            :         int ret;
     333                 :          5 :         uint8_t buf[512];
     334                 :            :         struct vsc *vendor_cap;
     335                 :            :         ssize_t cap_offset;
     336                 :            :         uint16_t vendor_cap_idx, cap_size, sparse_mmap_idx;
     337                 :          5 :         struct spdk_vfu_pci_device pci_dev;
     338                 :            :         uint8_t region_idx;
     339                 :            : 
     340   [ -  +  #  #  :          5 :         assert(endpoint->ops.get_device_info);
          #  #  #  #  #  
                      # ]
     341   [ #  #  #  #  :          5 :         ret = endpoint->ops.get_device_info(endpoint, &pci_dev);
          #  #  #  #  #  
                      # ]
     342         [ -  + ]:          5 :         if (ret) {
     343                 :          0 :                 SPDK_ERRLOG("%s: failed to get pci device info\n", spdk_vfu_get_endpoint_id(endpoint));
     344                 :          0 :                 return ret;
     345                 :            :         }
     346                 :            : 
     347   [ #  #  #  #  :          5 :         endpoint->vfu_ctx = vfu_create_ctx(VFU_TRANS_SOCK, endpoint->uuid, LIBVFIO_USER_FLAG_ATTACH_NB,
          #  #  #  #  #  
                      # ]
     348                 :          0 :                                            endpoint, VFU_DEV_TYPE_PCI);
     349   [ -  +  #  #  :          5 :         if (endpoint->vfu_ctx == NULL) {
                   #  # ]
     350                 :          0 :                 SPDK_ERRLOG("%s: error creating libvfio-user context\n", spdk_vfu_get_endpoint_id(endpoint));
     351                 :          0 :                 return -EFAULT;
     352                 :            :         }
     353   [ #  #  #  # ]:          5 :         vfu_setup_log(endpoint->vfu_ctx, tgt_log_cb, tgt_get_log_level());
     354                 :            : 
     355   [ #  #  #  # ]:          5 :         ret = vfu_pci_init(endpoint->vfu_ctx, VFU_PCI_TYPE_EXPRESS, PCI_HEADER_TYPE_NORMAL, 0);
     356         [ -  + ]:          5 :         if (ret < 0) {
     357   [ #  #  #  # ]:          0 :                 SPDK_ERRLOG("vfu_ctx %p failed to initialize PCI\n", endpoint->vfu_ctx);
     358                 :          0 :                 goto error;
     359                 :            :         }
     360                 :            : 
     361   [ #  #  #  #  :          5 :         vfu_pci_set_id(endpoint->vfu_ctx, pci_dev.id.vid, pci_dev.id.did, pci_dev.id.ssvid,
             #  #  #  # ]
     362         [ #  # ]:          5 :                        pci_dev.id.ssid);
     363   [ #  #  #  #  :          5 :         vfu_pci_set_class(endpoint->vfu_ctx, pci_dev.class.bcc, pci_dev.class.scc, pci_dev.class.pi);
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
     364                 :            : 
     365                 :            :         /* Add Vendor Capabilities */
     366   [ +  +  #  # ]:         25 :         for (vendor_cap_idx = 0; vendor_cap_idx < pci_dev.nr_vendor_caps; vendor_cap_idx++) {
     367         [ -  + ]:         20 :                 memset(buf, 0, sizeof(buf));
     368   [ #  #  #  #  :         20 :                 cap_size = endpoint->ops.get_vendor_capability(endpoint, buf, 256, vendor_cap_idx);
          #  #  #  #  #  
                      # ]
     369         [ +  - ]:         20 :                 if (cap_size) {
     370                 :         20 :                         vendor_cap = (struct vsc *)buf;
     371   [ -  +  #  #  :         20 :                         assert(vendor_cap->hdr.id == PCI_CAP_ID_VNDR);
          #  #  #  #  #  
                      # ]
     372   [ -  +  #  #  :         20 :                         assert(vendor_cap->size == cap_size);
             #  #  #  # ]
     373                 :            : 
     374   [ #  #  #  # ]:         20 :                         cap_offset = vfu_pci_add_capability(endpoint->vfu_ctx, 0, 0, vendor_cap);
     375         [ -  + ]:         20 :                         if (cap_offset < 0) {
     376   [ #  #  #  # ]:          0 :                                 SPDK_ERRLOG("vfu_ctx %p failed add vendor capability\n", endpoint->vfu_ctx);
     377                 :          0 :                                 ret = -EFAULT;
     378                 :          0 :                                 goto error;
     379                 :            :                         }
     380                 :          0 :                 }
     381                 :          0 :         }
     382                 :            : 
     383                 :            :         /* Add Standard PCI Capabilities */
     384   [ #  #  #  # ]:          5 :         cap_offset = vfu_pci_add_capability(endpoint->vfu_ctx, 0, 0, &pci_dev.pmcap);
     385         [ -  + ]:          5 :         if (cap_offset < 0) {
     386   [ #  #  #  # ]:          0 :                 SPDK_ERRLOG("vfu_ctx %p failed add pmcap\n", endpoint->vfu_ctx);
     387                 :          0 :                 ret = -EFAULT;
     388                 :          0 :                 goto error;
     389                 :            :         }
     390   [ -  +  -  +  :          5 :         SPDK_DEBUGLOG(vfu, "%s PM cap_offset %ld\n", spdk_vfu_get_endpoint_id(endpoint), cap_offset);
                   #  # ]
     391                 :            : 
     392   [ #  #  #  # ]:          5 :         cap_offset = vfu_pci_add_capability(endpoint->vfu_ctx, 0, 0, &pci_dev.pxcap);
     393         [ -  + ]:          5 :         if (cap_offset < 0) {
     394   [ #  #  #  # ]:          0 :                 SPDK_ERRLOG("vfu_ctx %p failed add pxcap\n", endpoint->vfu_ctx);
     395                 :          0 :                 ret = -EFAULT;
     396                 :          0 :                 goto error;
     397                 :            :         }
     398   [ -  +  -  +  :          5 :         SPDK_DEBUGLOG(vfu, "%s PX cap_offset %ld\n", spdk_vfu_get_endpoint_id(endpoint), cap_offset);
                   #  # ]
     399                 :            : 
     400   [ #  #  #  # ]:          5 :         cap_offset = vfu_pci_add_capability(endpoint->vfu_ctx, 0, 0, &pci_dev.msixcap);
     401         [ -  + ]:          5 :         if (cap_offset < 0) {
     402   [ #  #  #  # ]:          0 :                 SPDK_ERRLOG("vfu_ctx %p failed add msixcap\n", endpoint->vfu_ctx);
     403                 :          0 :                 ret = -EFAULT;
     404                 :          0 :                 goto error;
     405                 :            :         }
     406   [ -  +  -  +  :          5 :         SPDK_DEBUGLOG(vfu, "%s MSIX cap_offset %ld\n", spdk_vfu_get_endpoint_id(endpoint), cap_offset);
                   #  # ]
     407                 :            : 
     408                 :            :         /* Setup PCI Regions */
     409         [ +  + ]:         55 :         for (region_idx = 0; region_idx < VFU_PCI_DEV_NUM_REGIONS; region_idx++) {
     410         [ #  # ]:         50 :                 struct spdk_vfu_pci_region *region = &pci_dev.regions[region_idx];
     411                 :         50 :                 struct iovec sparse_mmap[SPDK_VFU_MAXIMUM_SPARSE_MMAP_REGIONS];
     412   [ +  +  #  #  :         50 :                 if (!region->len) {
                   #  # ]
     413                 :         30 :                         continue;
     414                 :            :                 }
     415                 :            : 
     416   [ +  +  #  #  :         20 :                 if (region->nr_sparse_mmaps) {
                   #  # ]
     417   [ -  +  #  #  :          5 :                         assert(region->nr_sparse_mmaps <= SPDK_VFU_MAXIMUM_SPARSE_MMAP_REGIONS);
             #  #  #  # ]
     418   [ +  +  #  #  :         10 :                         for (sparse_mmap_idx = 0; sparse_mmap_idx < region->nr_sparse_mmaps; sparse_mmap_idx++) {
                   #  # ]
     419   [ #  #  #  #  :          5 :                                 sparse_mmap[sparse_mmap_idx].iov_base = (void *)region->mmaps[sparse_mmap_idx].offset;
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  # ]
     420   [ #  #  #  #  :          5 :                                 sparse_mmap[sparse_mmap_idx].iov_len = region->mmaps[sparse_mmap_idx].len;
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  # ]
     421                 :          0 :                         }
     422                 :          0 :                 }
     423                 :            : 
     424   [ #  #  #  #  :         40 :                 ret = vfu_setup_region(endpoint->vfu_ctx, region_idx, region->len, region->access_cb, region->flags,
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
     425   [ +  +  #  #  :         20 :                                        region->nr_sparse_mmaps ? sparse_mmap : NULL, region->nr_sparse_mmaps,
          #  #  #  #  #  
                      # ]
     426   [ #  #  #  #  :          0 :                                        region->fd, region->offset);
             #  #  #  # ]
     427         [ -  + ]:         20 :                 if (ret) {
     428   [ #  #  #  # ]:          0 :                         SPDK_ERRLOG("vfu_ctx %p failed to setup region %u\n", endpoint->vfu_ctx, region_idx);
     429                 :          0 :                         goto error;
     430                 :            :                 }
     431   [ -  +  -  +  :         20 :                 SPDK_DEBUGLOG(vfu, "%s: region %u, len 0x%"PRIx64", callback %p, nr sparse mmaps %u, fd %d\n",
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                #  #  # ]
     432                 :            :                               spdk_vfu_get_endpoint_id(endpoint), region_idx, region->len, region->access_cb,
     433                 :            :                               region->nr_sparse_mmaps, region->fd);
     434                 :          0 :         }
     435                 :            : 
     436   [ #  #  #  # ]:          5 :         ret = vfu_setup_device_dma(endpoint->vfu_ctx, tgt_memory_region_add_cb,
     437                 :            :                                    tgt_memory_region_remove_cb);
     438         [ -  + ]:          5 :         if (ret < 0) {
     439   [ #  #  #  # ]:          0 :                 SPDK_ERRLOG("vfu_ctx %p failed to setup dma callback\n", endpoint->vfu_ctx);
     440                 :          0 :                 goto error;
     441                 :            :         }
     442                 :            : 
     443   [ +  -  #  #  :          5 :         if (endpoint->ops.reset_device) {
             #  #  #  # ]
     444   [ #  #  #  # ]:          5 :                 ret = vfu_setup_device_reset_cb(endpoint->vfu_ctx, tgt_device_reset_cb);
     445         [ -  + ]:          5 :                 if (ret < 0) {
     446   [ #  #  #  # ]:          0 :                         SPDK_ERRLOG("vfu_ctx %p failed to setup reset callback\n", endpoint->vfu_ctx);
     447                 :          0 :                         goto error;
     448                 :            :                 }
     449                 :          0 :         }
     450                 :            : 
     451   [ +  -  #  #  :          5 :         if (endpoint->ops.quiesce_device) {
             #  #  #  # ]
     452   [ #  #  #  # ]:          5 :                 vfu_setup_device_quiesce_cb(endpoint->vfu_ctx, tgt_device_quiesce_cb);
     453                 :          0 :         }
     454                 :            : 
     455   [ #  #  #  #  :          5 :         ret = vfu_setup_device_nr_irqs(endpoint->vfu_ctx, VFU_DEV_INTX_IRQ, pci_dev.nr_int_irqs);
                   #  # ]
     456         [ -  + ]:          5 :         if (ret < 0) {
     457   [ #  #  #  # ]:          0 :                 SPDK_ERRLOG("vfu_ctx %p failed to setup INTX\n", endpoint->vfu_ctx);
     458                 :          0 :                 goto error;
     459                 :            :         }
     460                 :            : 
     461   [ #  #  #  #  :          5 :         ret = vfu_setup_device_nr_irqs(endpoint->vfu_ctx, VFU_DEV_MSIX_IRQ, pci_dev.nr_msix_irqs);
                   #  # ]
     462         [ -  + ]:          5 :         if (ret < 0) {
     463   [ #  #  #  # ]:          0 :                 SPDK_ERRLOG("vfu_ctx %p failed to setup MSIX\n", endpoint->vfu_ctx);
     464                 :          0 :                 goto error;
     465                 :            :         }
     466                 :            : 
     467   [ #  #  #  # ]:          5 :         ret = vfu_realize_ctx(endpoint->vfu_ctx);
     468         [ -  + ]:          5 :         if (ret < 0) {
     469   [ #  #  #  # ]:          0 :                 SPDK_ERRLOG("vfu_ctx %p failed to realize\n", endpoint->vfu_ctx);
     470                 :          0 :                 goto error;
     471                 :            :         }
     472                 :            : 
     473   [ #  #  #  #  :          5 :         endpoint->pci_config_space = vfu_pci_get_config_space(endpoint->vfu_ctx);
             #  #  #  # ]
     474   [ -  +  #  #  :          5 :         assert(endpoint->pci_config_space != NULL);
             #  #  #  # ]
     475   [ #  #  #  #  :          5 :         init_pci_config_space(endpoint->pci_config_space, pci_dev.intr_ipin);
                   #  # ]
     476                 :            : 
     477   [ -  +  #  # ]:          5 :         assert(cap_offset != 0);
     478   [ #  #  #  #  :          5 :         endpoint->msix = (struct msixcap *)((uint8_t *)endpoint->pci_config_space + cap_offset);
          #  #  #  #  #  
                      # ]
     479                 :            : 
     480                 :          5 :         return 0;
     481                 :            : 
     482                 :          0 : error:
     483   [ #  #  #  #  :          0 :         if (endpoint->vfu_ctx) {
                   #  # ]
     484   [ #  #  #  # ]:          0 :                 vfu_destroy_ctx(endpoint->vfu_ctx);
     485                 :          0 :         }
     486                 :          0 :         return ret;
     487                 :          0 : }
     488                 :            : 
     489                 :            : static int
     490                 :          5 : vfu_parse_core_mask(const char *mask, struct spdk_cpuset *cpumask)
     491                 :            : {
     492                 :            :         int rc;
     493                 :          5 :         struct spdk_cpuset negative_vfu_mask;
     494                 :            : 
     495         [ -  + ]:          5 :         if (cpumask == NULL) {
     496                 :          0 :                 return -1;
     497                 :            :         }
     498                 :            : 
     499         [ +  + ]:          5 :         if (mask == NULL) {
     500                 :          3 :                 spdk_cpuset_copy(cpumask, &g_tgt_core_mask);
     501                 :          3 :                 return 0;
     502                 :            :         }
     503                 :            : 
     504                 :          2 :         rc = spdk_cpuset_parse(cpumask, mask);
     505         [ -  + ]:          2 :         if (rc < 0) {
     506                 :          0 :                 SPDK_ERRLOG("invalid cpumask %s\n", mask);
     507                 :          0 :                 return -1;
     508                 :            :         }
     509                 :            : 
     510                 :          2 :         spdk_cpuset_copy(&negative_vfu_mask, &g_tgt_core_mask);
     511                 :          2 :         spdk_cpuset_negate(&negative_vfu_mask);
     512                 :          2 :         spdk_cpuset_and(&negative_vfu_mask, cpumask);
     513                 :            : 
     514         [ -  + ]:          2 :         if (spdk_cpuset_count(&negative_vfu_mask) != 0) {
     515                 :          0 :                 SPDK_ERRLOG("one of selected cpu is outside of core mask(=%s)\n",
     516                 :            :                             spdk_cpuset_fmt(&g_tgt_core_mask));
     517                 :          0 :                 return -1;
     518                 :            :         }
     519                 :            : 
     520                 :          2 :         spdk_cpuset_and(cpumask, &g_tgt_core_mask);
     521                 :            : 
     522         [ -  + ]:          2 :         if (spdk_cpuset_count(cpumask) == 0) {
     523                 :          0 :                 SPDK_ERRLOG("no cpu is selected among core mask(=%s)\n",
     524                 :            :                             spdk_cpuset_fmt(&g_tgt_core_mask));
     525                 :          0 :                 return -1;
     526                 :            :         }
     527                 :            : 
     528                 :          2 :         return 0;
     529                 :          0 : }
     530                 :            : 
     531                 :            : static void
     532                 :          5 : tgt_endpoint_start_thread(void *arg1)
     533                 :            : {
     534                 :          5 :         struct spdk_vfu_endpoint *endpoint = arg1;
     535                 :            : 
     536   [ #  #  #  # ]:          5 :         endpoint->accept_poller = SPDK_POLLER_REGISTER(tgt_accept_poller, endpoint, 1000);
     537   [ -  +  #  #  :          5 :         assert(endpoint->accept_poller != NULL);
             #  #  #  # ]
     538                 :          5 : }
     539                 :            : 
     540                 :            : static void
     541                 :          9 : tgt_endpoint_thread_try_exit(void *arg1)
     542                 :            : {
     543                 :          9 :         struct spdk_vfu_endpoint *endpoint = arg1;
     544                 :            :         static spdk_vfu_fini_cb fini_cb = NULL;
     545                 :            :         int res;
     546                 :            : 
     547   [ #  #  #  #  :          9 :         res = endpoint->ops.destruct(endpoint);
          #  #  #  #  #  
                      # ]
     548         [ +  + ]:          9 :         if (res == -EAGAIN) {
     549                 :            :                 /* Let's retry */
     550   [ #  #  #  # ]:          4 :                 spdk_thread_send_msg(endpoint->thread, tgt_endpoint_thread_try_exit, endpoint);
     551                 :          4 :                 return;
     552         [ -  + ]:          5 :         } else if (res) {
     553                 :            :                 /* We're ignoring this error for now as we have nothing to do with it */
     554                 :          0 :                 SPDK_ERRLOG("Endpoint destruct failed with %d\n", res);
     555                 :          0 :         }
     556                 :            : 
     557                 :          5 :         free(endpoint);
     558                 :            : 
     559         [ -  + ]:          5 :         pthread_mutex_lock(&g_endpoint_lock);
     560         [ +  + ]:          5 :         if (g_fini_cb) { /* called due to spdk_vfu_fini() */
     561                 :          3 :                 g_fini_endpoint_cnt--;
     562                 :            : 
     563         [ +  - ]:          3 :                 if (!g_fini_endpoint_cnt) {
     564                 :          3 :                         fini_cb = g_fini_cb;
     565                 :          3 :                         g_fini_cb = NULL;
     566                 :          0 :                 }
     567                 :          0 :         }
     568         [ -  + ]:          5 :         pthread_mutex_unlock(&g_endpoint_lock);
     569                 :            : 
     570         [ +  + ]:          5 :         if (fini_cb) {
     571   [ #  #  #  # ]:          3 :                 fini_cb();
     572                 :          0 :         }
     573                 :            : 
     574                 :          5 :         spdk_thread_exit(spdk_get_thread());
     575                 :          0 : }
     576                 :            : 
     577                 :            : static void
     578                 :          5 : tgt_endpoint_thread_exit(void *arg1)
     579                 :            : {
     580                 :          5 :         struct spdk_vfu_endpoint *endpoint = arg1;
     581                 :            : 
     582         [ #  # ]:          5 :         spdk_poller_unregister(&endpoint->accept_poller);
     583         [ #  # ]:          5 :         spdk_poller_unregister(&endpoint->vfu_ctx_poller);
     584                 :            : 
     585                 :            :         /* Ensure the attached device is stopped before destroying the vfu context */
     586   [ +  -  #  #  :          5 :         if (endpoint->ops.detach_device) {
             #  #  #  # ]
     587   [ #  #  #  #  :          5 :                 endpoint->ops.detach_device(endpoint);
          #  #  #  #  #  
                      # ]
     588                 :          0 :         }
     589                 :            : 
     590   [ +  -  #  #  :          5 :         if (endpoint->vfu_ctx) {
                   #  # ]
     591   [ #  #  #  # ]:          5 :                 vfu_destroy_ctx(endpoint->vfu_ctx);
     592                 :          0 :         }
     593                 :            : 
     594                 :          5 :         tgt_endpoint_thread_try_exit(endpoint);
     595                 :          5 : }
     596                 :            : 
     597                 :            : int
     598                 :          5 : spdk_vfu_create_endpoint(const char *endpoint_name, const char *cpumask_str,
     599                 :            :                          const char *dev_type_name)
     600                 :            : {
     601                 :            :         char *basename;
     602                 :          5 :         char uuid[PATH_MAX] = "";
     603                 :          5 :         struct spdk_cpuset cpumask = {};
     604                 :            :         struct spdk_vfu_endpoint *endpoint;
     605                 :            :         struct spdk_vfu_endpoint_ops *ops;
     606                 :          5 :         int ret = 0;
     607                 :            : 
     608                 :          5 :         ret = vfu_parse_core_mask(cpumask_str, &cpumask);
     609         [ -  + ]:          5 :         if (ret) {
     610                 :          0 :                 return ret;
     611                 :            :         }
     612                 :            : 
     613   [ -  +  -  + ]:          5 :         if (strlen(endpoint_name) >= SPDK_VFU_MAX_NAME_LEN - 1) {
     614                 :          0 :                 return -ENAMETOOLONG;
     615                 :            :         }
     616                 :            : 
     617         [ -  + ]:          5 :         if (spdk_vfu_get_endpoint_by_name(endpoint_name)) {
     618                 :          0 :                 SPDK_ERRLOG("%s already exist\n", endpoint_name);
     619                 :          0 :                 return -EEXIST;
     620                 :            :         }
     621                 :            : 
     622                 :            :         /* Find supported PCI device type */
     623                 :          5 :         ops = tgt_get_pci_device_ops(dev_type_name);
     624         [ -  + ]:          5 :         if (!ops) {
     625                 :          0 :                 SPDK_ERRLOG("Request %s device type isn't registered\n", dev_type_name);
     626                 :          0 :                 return -ENOTSUP;
     627                 :            :         }
     628                 :            : 
     629                 :          5 :         basename = tgt_get_base_path();
     630         [ -  + ]:          5 :         if (snprintf(uuid, sizeof(uuid), "%s%s", basename, endpoint_name) >= (int)sizeof(uuid)) {
     631                 :          0 :                 SPDK_ERRLOG("Resulting socket path for endpoint %s is too long: %s%s\n",
     632                 :            :                             endpoint_name, basename, endpoint_name);
     633                 :          0 :                 return -EINVAL;
     634                 :            :         }
     635                 :            : 
     636                 :          5 :         endpoint = calloc(1, sizeof(*endpoint));
     637         [ -  + ]:          5 :         if (!endpoint) {
     638                 :          0 :                 return -ENOMEM;
     639                 :            :         }
     640                 :            : 
     641   [ #  #  #  #  :          5 :         endpoint->endpoint_ctx = ops->init(endpoint, basename, endpoint_name);
          #  #  #  #  #  
                #  #  # ]
     642   [ -  +  #  #  :          5 :         if (!endpoint->endpoint_ctx) {
                   #  # ]
     643                 :          0 :                 free(endpoint);
     644                 :          0 :                 return -EINVAL;
     645                 :            :         }
     646         [ #  # ]:          5 :         endpoint->ops = *ops;
     647         [ #  # ]:          5 :         snprintf(endpoint->name, SPDK_VFU_MAX_NAME_LEN, "%s", endpoint_name);
     648         [ #  # ]:          5 :         snprintf(endpoint->uuid, sizeof(uuid), "%s", uuid);
     649                 :            : 
     650   [ -  +  -  +  :          5 :         SPDK_DEBUGLOG(vfu, "Construct endpoint %s\n", endpoint_name);
                   #  # ]
     651                 :            :         /* Endpoint realize */
     652                 :          5 :         ret = tgt_endpoint_realize(endpoint);
     653         [ -  + ]:          5 :         if (ret) {
     654   [ #  #  #  #  :          0 :                 endpoint->ops.destruct(endpoint);
          #  #  #  #  #  
                      # ]
     655                 :          0 :                 free(endpoint);
     656                 :          0 :                 return ret;
     657                 :            :         }
     658                 :            : 
     659   [ #  #  #  # ]:          5 :         endpoint->thread = spdk_thread_create(endpoint_name, &cpumask);
     660   [ -  +  #  #  :          5 :         if (!endpoint->thread) {
                   #  # ]
     661   [ #  #  #  #  :          0 :                 endpoint->ops.destruct(endpoint);
          #  #  #  #  #  
                      # ]
     662   [ #  #  #  # ]:          0 :                 vfu_destroy_ctx(endpoint->vfu_ctx);
     663                 :          0 :                 free(endpoint);
     664                 :          0 :                 return -EFAULT;
     665                 :            :         }
     666                 :            : 
     667                 :          5 :         ret = 0;
     668         [ #  # ]:          5 :         pthread_mutex_lock(&g_endpoint_lock);
     669         [ +  - ]:          5 :         if (!g_fini_cb) {
     670   [ #  #  #  #  :          5 :                 TAILQ_INSERT_TAIL(&g_endpoint, endpoint, link);
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  #  
                      # ]
     671                 :          0 :         } else { /* spdk_vfu_fini has been called */
     672                 :          0 :                 ret = -EPERM;
     673                 :            :         }
     674         [ #  # ]:          5 :         pthread_mutex_unlock(&g_endpoint_lock);
     675                 :            : 
     676         [ -  + ]:          5 :         if (ret) {
     677                 :            :                 /* we're in the process of destruction, no new endpoint creation is allowed */
     678   [ #  #  #  # ]:          0 :                 spdk_thread_destroy(endpoint->thread);
     679   [ #  #  #  #  :          0 :                 endpoint->ops.destruct(endpoint);
          #  #  #  #  #  
                      # ]
     680   [ #  #  #  # ]:          0 :                 vfu_destroy_ctx(endpoint->vfu_ctx);
     681                 :          0 :                 free(endpoint);
     682                 :          0 :                 return -EFAULT;
     683                 :            :         }
     684                 :            : 
     685   [ #  #  #  # ]:          5 :         spdk_thread_send_msg(endpoint->thread, tgt_endpoint_start_thread, endpoint);
     686                 :            : 
     687                 :          5 :         return 0;
     688                 :          0 : }
     689                 :            : 
     690                 :            : int
     691                 :          2 : spdk_vfu_delete_endpoint(const char *endpoint_name)
     692                 :            : {
     693                 :            :         struct spdk_vfu_endpoint *endpoint;
     694                 :            : 
     695                 :          2 :         endpoint = spdk_vfu_get_endpoint_by_name(endpoint_name);
     696         [ -  + ]:          2 :         if (!endpoint) {
     697                 :          0 :                 SPDK_ERRLOG("%s doesn't exist\n", endpoint_name);
     698                 :          0 :                 return -ENOENT;
     699                 :            :         }
     700                 :            : 
     701                 :          2 :         SPDK_NOTICELOG("Destruct endpoint %s\n", endpoint_name);
     702                 :            : 
     703         [ -  + ]:          2 :         pthread_mutex_lock(&g_endpoint_lock);
     704   [ +  +  #  #  :          2 :         TAILQ_REMOVE(&g_endpoint, endpoint, link);
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  # ]
     705         [ -  + ]:          2 :         pthread_mutex_unlock(&g_endpoint_lock);
     706   [ #  #  #  # ]:          2 :         spdk_thread_send_msg(endpoint->thread, tgt_endpoint_thread_exit, endpoint);
     707                 :            : 
     708                 :          2 :         return 0;
     709                 :          0 : }
     710                 :            : 
     711                 :            : const char *
     712                 :        276 : spdk_vfu_get_endpoint_id(struct spdk_vfu_endpoint *endpoint)
     713                 :            : {
     714         [ #  # ]:        276 :         return endpoint->uuid;
     715                 :            : }
     716                 :            : 
     717                 :            : const char *
     718                 :          7 : spdk_vfu_get_endpoint_name(struct spdk_vfu_endpoint *endpoint)
     719                 :            : {
     720         [ #  # ]:          7 :         return endpoint->name;
     721                 :            : }
     722                 :            : 
     723                 :            : vfu_ctx_t *
     724                 :    4112822 : spdk_vfu_get_vfu_ctx(struct spdk_vfu_endpoint *endpoint)
     725                 :            : {
     726   [ #  #  #  # ]:    4112822 :         return endpoint->vfu_ctx;
     727                 :            : }
     728                 :            : 
     729                 :            : void *
     730                 :       1854 : spdk_vfu_get_endpoint_private(struct spdk_vfu_endpoint *endpoint)
     731                 :            : {
     732   [ #  #  #  # ]:       1854 :         return endpoint->endpoint_ctx;
     733                 :            : }
     734                 :            : 
     735                 :            : bool
     736                 :     290858 : spdk_vfu_endpoint_msix_enabled(struct spdk_vfu_endpoint *endpoint)
     737                 :            : {
     738   [ #  #  #  #  :     290858 :         return endpoint->msix->mxc.mxe;
             #  #  #  # ]
     739                 :            : }
     740                 :            : 
     741                 :            : bool
     742                 :          0 : spdk_vfu_endpoint_intx_enabled(struct spdk_vfu_endpoint *endpoint)
     743                 :            : {
     744   [ #  #  #  #  :          0 :         return !endpoint->pci_config_space->hdr.cmd.id;
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
     745                 :            : }
     746                 :            : 
     747                 :            : void *
     748                 :          0 : spdk_vfu_endpoint_get_pci_config(struct spdk_vfu_endpoint *endpoint)
     749                 :            : {
     750   [ #  #  #  # ]:          0 :         return (void *)endpoint->pci_config_space;
     751                 :            : }
     752                 :            : 
     753                 :            : void
     754                 :         82 : spdk_vfu_init(spdk_vfu_init_cb init_cb)
     755                 :            : {
     756                 :            :         uint32_t i;
     757                 :            :         size_t len;
     758                 :            : 
     759   [ +  -  +  -  :         82 :         if (g_endpoint_path_dirname[0] == '\0') {
                   -  + ]
     760         [ +  + ]:         82 :                 if (getcwd(g_endpoint_path_dirname, sizeof(g_endpoint_path_dirname) - 2) == NULL) {
     761                 :          0 :                         SPDK_ERRLOG("getcwd failed\n");
     762                 :          0 :                         return;
     763                 :            :                 }
     764                 :            : 
     765         [ +  - ]:         82 :                 len = strlen(g_endpoint_path_dirname);
     766   [ +  -  +  -  :         82 :                 if (g_endpoint_path_dirname[len - 1] != '/') {
             +  -  -  + ]
     767   [ +  -  +  -  :         82 :                         g_endpoint_path_dirname[len] = '/';
                   +  - ]
     768   [ +  -  +  -  :         82 :                         g_endpoint_path_dirname[len + 1] = '\0';
                   +  - ]
     769                 :         21 :                 }
     770                 :         21 :         }
     771                 :            : 
     772                 :         82 :         spdk_cpuset_zero(&g_tgt_core_mask);
     773         [ +  + ]:        197 :         SPDK_ENV_FOREACH_CORE(i) {
     774                 :        115 :                 spdk_cpuset_set_cpu(&g_tgt_core_mask, i, true);
     775                 :         28 :         }
     776                 :            : 
     777   [ -  +  +  - ]:         82 :         init_cb(0);
     778                 :         21 : }
     779                 :            : 
     780                 :            : void *
     781                 :   13313672 : spdk_vfu_map_one(struct spdk_vfu_endpoint *endpoint, uint64_t addr, uint64_t len, dma_sg_t *sg,
     782                 :            :                  struct iovec *iov,
     783                 :            :                  int prot)
     784                 :            : {
     785                 :            :         int ret;
     786                 :            : 
     787   [ -  +  #  # ]:   13313672 :         assert(endpoint != NULL);
     788   [ -  +  #  #  :   13313672 :         assert(endpoint->vfu_ctx != NULL);
             #  #  #  # ]
     789   [ -  +  #  # ]:   13313672 :         assert(sg != NULL);
     790   [ -  +  #  # ]:   13313672 :         assert(iov != NULL);
     791                 :            : 
     792   [ #  #  #  # ]:   13313672 :         ret = vfu_addr_to_sgl(endpoint->vfu_ctx, (void *)(uintptr_t)addr, len, sg, 1, prot);
     793         [ +  + ]:   13313672 :         if (ret < 0) {
     794                 :         20 :                 return NULL;
     795                 :            :         }
     796                 :            : 
     797   [ #  #  #  # ]:   13313652 :         ret = vfu_sgl_get(endpoint->vfu_ctx, sg, iov, 1, 0);
     798         [ -  + ]:   13313652 :         if (ret != 0) {
     799                 :          0 :                 return NULL;
     800                 :            :         }
     801                 :            : 
     802   [ -  +  #  #  :   13313652 :         assert(iov->iov_base != NULL);
             #  #  #  # ]
     803   [ #  #  #  # ]:   13313652 :         return iov->iov_base;
     804                 :          0 : }
     805                 :            : 
     806                 :            : void
     807                 :         84 : spdk_vfu_unmap_sg(struct spdk_vfu_endpoint *endpoint, dma_sg_t *sg, struct iovec *iov, int iovcnt)
     808                 :            : {
     809   [ -  +  #  # ]:         84 :         assert(endpoint != NULL);
     810   [ -  +  #  #  :         84 :         assert(endpoint->vfu_ctx != NULL);
             #  #  #  # ]
     811   [ -  +  #  # ]:         84 :         assert(sg != NULL);
     812   [ -  +  #  # ]:         84 :         assert(iov != NULL);
     813                 :            : 
     814   [ #  #  #  # ]:         84 :         vfu_sgl_put(endpoint->vfu_ctx, sg, iov, iovcnt);
     815                 :         84 : }
     816                 :            : 
     817                 :            : void
     818                 :         82 : spdk_vfu_fini(spdk_vfu_fini_cb fini_cb)
     819                 :            : {
     820                 :            :         struct spdk_vfu_endpoint *endpoint, *tmp;
     821                 :            :         struct tgt_pci_device_ops *ops, *ops_tmp;
     822                 :         82 :         uint32_t endpoint_cnt = 0;
     823                 :            : 
     824         [ +  + ]:         82 :         pthread_mutex_lock(&g_endpoint_lock);
     825   [ +  +  #  # ]:         82 :         assert(!g_fini_cb);
     826   [ +  +  +  -  :        328 :         TAILQ_FOREACH_SAFE(ops, &g_pci_device_ops, link, ops_tmp) {
          +  -  +  -  +  
                      + ]
     827   [ +  +  +  -  :        246 :                 TAILQ_REMOVE(&g_pci_device_ops, ops, link);
          +  -  +  +  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
             +  -  +  - ]
     828                 :        246 :                 free(ops);
     829                 :         63 :         }
     830                 :            : 
     831   [ +  +  #  #  :         85 :         TAILQ_FOREACH_SAFE(endpoint, &g_endpoint, link, tmp) {
          #  #  #  #  +  
                      - ]
     832   [ -  +  #  #  :          3 :                 TAILQ_REMOVE(&g_endpoint, endpoint, link);
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  # ]
     833                 :          3 :                 endpoint_cnt++;
     834   [ #  #  #  # ]:          3 :                 spdk_thread_send_msg(endpoint->thread, tgt_endpoint_thread_exit, endpoint);
     835                 :          0 :         }
     836                 :            : 
     837                 :            :         /* NOTE: g_fini_cb and g_fini_endpoint_cnt are accessed under the same mutex so it's safe to assign them here */
     838         [ +  + ]:         82 :         if (endpoint_cnt) {
     839                 :          3 :                 g_fini_endpoint_cnt = endpoint_cnt;
     840                 :          3 :                 g_fini_cb = fini_cb;
     841                 :          0 :         }
     842         [ +  + ]:         82 :         pthread_mutex_unlock(&g_endpoint_lock);
     843                 :            : 
     844         [ +  + ]:         82 :         if (!endpoint_cnt) {
     845   [ -  +  +  - ]:         79 :                 fini_cb();
     846                 :         21 :         }
     847                 :         82 : }
     848                 :        281 : SPDK_LOG_REGISTER_COMPONENT(vfu)

Generated by: LCOV version 1.15