LCOV - code coverage report
Current view: top level - spdk/lib/vfu_tgt - tgt_endpoint.c (source / functions) Hit Total Coverage
Test: Combined Lines: 308 405 76.0 %
Date: 2024-07-13 09:44:24 Functions: 29 32 90.6 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 156 288 54.2 %

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

Generated by: LCOV version 1.14