LCOV - code coverage report
Current view: top level - lib/nvme - nvme_vfio_user.c (source / functions) Hit Total Coverage
Test: ut_cov_unit.info Lines: 0 171 0.0 %
Date: 2024-12-14 14:10:06 Functions: 0 18 0.0 %

          Line data    Source code
       1             : /*   SPDX-License-Identifier: BSD-3-Clause
       2             :  *   Copyright (C) 2020 Intel Corporation. All rights reserved.
       3             :  */
       4             : 
       5             : /* VFIO transport extensions for spdk_nvme_ctrlr */
       6             : 
       7             : #include "spdk/stdinc.h"
       8             : #include "spdk/env.h"
       9             : #include "spdk/likely.h"
      10             : #include "spdk/string.h"
      11             : #include "spdk/vfio_user_pci.h"
      12             : #include "nvme_internal.h"
      13             : #include "nvme_pcie_internal.h"
      14             : 
      15             : #include <linux/vfio.h>
      16             : 
      17             : #define NVME_MAX_XFER_SIZE              (131072)
      18             : #define NVME_MAX_SGES                   (1)
      19             : 
      20             : struct nvme_vfio_ctrlr {
      21             :         struct nvme_pcie_ctrlr pctrlr;
      22             : 
      23             :         volatile uint32_t *doorbell_base;
      24             :         struct vfio_device *dev;
      25             : };
      26             : 
      27             : static inline struct nvme_vfio_ctrlr *
      28           0 : nvme_vfio_ctrlr(struct spdk_nvme_ctrlr *ctrlr)
      29             : {
      30           0 :         struct nvme_pcie_ctrlr *pctrlr = nvme_pcie_ctrlr(ctrlr);
      31             : 
      32           0 :         return SPDK_CONTAINEROF(pctrlr, struct nvme_vfio_ctrlr, pctrlr);
      33           0 : }
      34             : 
      35             : static volatile struct spdk_nvme_registers *
      36           0 : nvme_vfio_ctrlr_get_registers(struct spdk_nvme_ctrlr *ctrlr)
      37             : {
      38           0 :         struct nvme_vfio_ctrlr *vctrlr = nvme_vfio_ctrlr(ctrlr);
      39             : 
      40           0 :         return vctrlr->pctrlr.regs;
      41           0 : }
      42             : 
      43             : static int
      44           0 : nvme_vfio_ctrlr_set_reg_4(struct spdk_nvme_ctrlr *ctrlr, uint32_t offset, uint32_t value)
      45             : {
      46           0 :         struct nvme_vfio_ctrlr *vctrlr = nvme_vfio_ctrlr(ctrlr);
      47             : 
      48           0 :         assert(offset <= sizeof(struct spdk_nvme_registers) - 4);
      49           0 :         SPDK_DEBUGLOG(nvme_vfio, "ctrlr %s: offset 0x%x, value 0x%x\n", ctrlr->trid.traddr, offset, value);
      50             : 
      51           0 :         return spdk_vfio_user_pci_bar_access(vctrlr->dev, VFIO_PCI_BAR0_REGION_INDEX,
      52           0 :                                              offset, 4, &value, true);
      53           0 : }
      54             : 
      55             : static int
      56           0 : nvme_vfio_ctrlr_set_reg_8(struct spdk_nvme_ctrlr *ctrlr, uint32_t offset, uint64_t value)
      57             : {
      58           0 :         struct nvme_vfio_ctrlr *vctrlr = nvme_vfio_ctrlr(ctrlr);
      59             : 
      60           0 :         assert(offset <= sizeof(struct spdk_nvme_registers) - 8);
      61           0 :         SPDK_DEBUGLOG(nvme_vfio, "ctrlr %s: offset 0x%x, value 0x%"PRIx64"\n", ctrlr->trid.traddr, offset,
      62             :                       value);
      63             : 
      64           0 :         return spdk_vfio_user_pci_bar_access(vctrlr->dev, VFIO_PCI_BAR0_REGION_INDEX,
      65           0 :                                              offset, 8, &value, true);
      66           0 : }
      67             : 
      68             : static int
      69           0 : nvme_vfio_ctrlr_get_reg_4(struct spdk_nvme_ctrlr *ctrlr, uint32_t offset, uint32_t *value)
      70             : {
      71           0 :         struct nvme_vfio_ctrlr *vctrlr = nvme_vfio_ctrlr(ctrlr);
      72           0 :         int ret;
      73             : 
      74           0 :         assert(offset <= sizeof(struct spdk_nvme_registers) - 4);
      75             : 
      76           0 :         ret = spdk_vfio_user_pci_bar_access(vctrlr->dev, VFIO_PCI_BAR0_REGION_INDEX,
      77           0 :                                             offset, 4, value, false);
      78           0 :         if (ret != 0) {
      79           0 :                 SPDK_ERRLOG("ctrlr %p, offset %x\n", ctrlr, offset);
      80           0 :                 return ret;
      81             :         }
      82             : 
      83           0 :         SPDK_DEBUGLOG(nvme_vfio, "ctrlr %s: offset 0x%x, value 0x%x\n", ctrlr->trid.traddr, offset, *value);
      84             : 
      85           0 :         return 0;
      86           0 : }
      87             : 
      88             : static int
      89           0 : nvme_vfio_ctrlr_get_reg_8(struct spdk_nvme_ctrlr *ctrlr, uint32_t offset, uint64_t *value)
      90             : {
      91           0 :         struct nvme_vfio_ctrlr *vctrlr = nvme_vfio_ctrlr(ctrlr);
      92           0 :         int ret;
      93             : 
      94           0 :         assert(offset <= sizeof(struct spdk_nvme_registers) - 8);
      95             : 
      96           0 :         ret = spdk_vfio_user_pci_bar_access(vctrlr->dev, VFIO_PCI_BAR0_REGION_INDEX,
      97           0 :                                             offset, 8, value, false);
      98           0 :         if (ret != 0) {
      99           0 :                 SPDK_ERRLOG("ctrlr %p, offset %x\n", ctrlr, offset);
     100           0 :                 return ret;
     101             :         }
     102             : 
     103           0 :         SPDK_DEBUGLOG(nvme_vfio, "ctrlr %s: offset 0x%x, value 0x%"PRIx64"\n", ctrlr->trid.traddr, offset,
     104             :                       *value);
     105             : 
     106           0 :         return 0;
     107           0 : }
     108             : 
     109             : static int
     110           0 : nvme_vfio_ctrlr_set_asq(struct spdk_nvme_ctrlr *ctrlr, uint64_t value)
     111             : {
     112           0 :         return nvme_vfio_ctrlr_set_reg_8(ctrlr, offsetof(struct spdk_nvme_registers, asq),
     113           0 :                                          value);
     114             : }
     115             : 
     116             : static int
     117           0 : nvme_vfio_ctrlr_set_acq(struct spdk_nvme_ctrlr *ctrlr, uint64_t value)
     118             : {
     119           0 :         return nvme_vfio_ctrlr_set_reg_8(ctrlr, offsetof(struct spdk_nvme_registers, acq),
     120           0 :                                          value);
     121             : }
     122             : 
     123             : static int
     124           0 : nvme_vfio_ctrlr_set_aqa(struct spdk_nvme_ctrlr *ctrlr, const union spdk_nvme_aqa_register *aqa)
     125             : {
     126           0 :         return nvme_vfio_ctrlr_set_reg_4(ctrlr, offsetof(struct spdk_nvme_registers, aqa.raw),
     127           0 :                                          aqa->raw);
     128             : }
     129             : 
     130             : static int
     131           0 : nvme_vfio_setup_bar0(struct nvme_vfio_ctrlr *vctrlr)
     132             : {
     133           0 :         void *doorbell;
     134             : 
     135           0 :         doorbell = spdk_vfio_user_get_bar_addr(vctrlr->dev, 0, 0x1000, 0x1000);
     136           0 :         if (!doorbell) {
     137           0 :                 return -EINVAL;
     138             :         }
     139             : 
     140           0 :         vctrlr->doorbell_base = (volatile uint32_t *)doorbell;
     141           0 :         return 0;
     142           0 : }
     143             : 
     144             : static struct spdk_nvme_ctrlr *
     145           0 :         nvme_vfio_ctrlr_construct(const struct spdk_nvme_transport_id *trid,
     146             :                           const struct spdk_nvme_ctrlr_opts *opts,
     147             :                           void *devhandle)
     148             : {
     149           0 :         struct nvme_vfio_ctrlr *vctrlr;
     150           0 :         struct nvme_pcie_ctrlr *pctrlr;
     151           0 :         uint16_t cmd_reg;
     152           0 :         union spdk_nvme_cap_register cap;
     153           0 :         int ret;
     154           0 :         char ctrlr_path[PATH_MAX];
     155             : 
     156           0 :         snprintf(ctrlr_path, sizeof(ctrlr_path), "%s/cntrl", trid->traddr);
     157           0 :         ret = access(ctrlr_path, F_OK);
     158           0 :         if (ret != 0) {
     159           0 :                 SPDK_ERRLOG("Access path %s failed\n", ctrlr_path);
     160           0 :                 return NULL;
     161             :         }
     162             : 
     163           0 :         vctrlr = calloc(1, sizeof(*vctrlr));
     164           0 :         if (!vctrlr) {
     165           0 :                 return NULL;
     166             :         }
     167             : 
     168           0 :         vctrlr->dev = spdk_vfio_user_setup(ctrlr_path);
     169           0 :         if (!vctrlr->dev) {
     170           0 :                 SPDK_ERRLOG("Error to setup vfio device\n");
     171           0 :                 free(vctrlr);
     172           0 :                 return NULL;
     173             :         }
     174             : 
     175           0 :         ret = nvme_vfio_setup_bar0(vctrlr);
     176           0 :         if (ret != 0) {
     177           0 :                 SPDK_ERRLOG("Error to get device BAR0\n");
     178           0 :                 goto exit;
     179             :         }
     180             : 
     181           0 :         pctrlr = &vctrlr->pctrlr;
     182           0 :         pctrlr->doorbell_base = vctrlr->doorbell_base;
     183           0 :         pctrlr->ctrlr.is_removed = false;
     184           0 :         pctrlr->ctrlr.opts = *opts;
     185           0 :         pctrlr->ctrlr.trid = *trid;
     186           0 :         pctrlr->ctrlr.opts.use_cmb_sqs = false;
     187           0 :         pctrlr->ctrlr.opts.admin_queue_size = spdk_max(pctrlr->ctrlr.opts.admin_queue_size,
     188             :                                               NVME_PCIE_MIN_ADMIN_QUEUE_SIZE);
     189             : 
     190           0 :         ret = nvme_ctrlr_construct(&pctrlr->ctrlr);
     191           0 :         if (ret != 0) {
     192           0 :                 goto exit;
     193             :         }
     194             : 
     195             :         /* Enable PCI busmaster and disable INTx */
     196           0 :         ret = spdk_vfio_user_pci_bar_access(vctrlr->dev, VFIO_PCI_CONFIG_REGION_INDEX, 4, 2,
     197             :                                             &cmd_reg, false);
     198           0 :         if (ret != 0) {
     199           0 :                 nvme_ctrlr_destruct(&pctrlr->ctrlr);
     200           0 :                 SPDK_ERRLOG("Read PCI CMD REG failed\n");
     201           0 :                 goto exit;
     202             :         }
     203           0 :         cmd_reg |= 0x404;
     204           0 :         ret = spdk_vfio_user_pci_bar_access(vctrlr->dev, VFIO_PCI_CONFIG_REGION_INDEX, 4, 2,
     205             :                                             &cmd_reg, true);
     206           0 :         if (ret != 0) {
     207           0 :                 nvme_ctrlr_destruct(&pctrlr->ctrlr);
     208           0 :                 SPDK_ERRLOG("Write PCI CMD REG failed\n");
     209           0 :                 goto exit;
     210             :         }
     211             : 
     212           0 :         if (nvme_ctrlr_get_cap(&pctrlr->ctrlr, &cap)) {
     213           0 :                 nvme_ctrlr_destruct(&pctrlr->ctrlr);
     214           0 :                 SPDK_ERRLOG("get_cap() failed\n");
     215           0 :                 goto exit;
     216             :         }
     217             : 
     218             :         /* Doorbell stride is 2 ^ (dstrd + 2),
     219             :          * but we want multiples of 4, so drop the + 2 */
     220           0 :         pctrlr->doorbell_stride_u32 = 1 << cap.bits.dstrd;
     221             : 
     222           0 :         ret = nvme_pcie_ctrlr_construct_admin_qpair(&pctrlr->ctrlr, pctrlr->ctrlr.opts.admin_queue_size);
     223           0 :         if (ret != 0) {
     224           0 :                 nvme_ctrlr_destruct(&pctrlr->ctrlr);
     225           0 :                 goto exit;
     226             :         }
     227             : 
     228             :         /* Construct the primary process properties */
     229           0 :         ret = nvme_ctrlr_add_process(&pctrlr->ctrlr, 0);
     230           0 :         if (ret != 0) {
     231           0 :                 nvme_ctrlr_destruct(&pctrlr->ctrlr);
     232           0 :                 goto exit;
     233             :         }
     234             : 
     235           0 :         return &pctrlr->ctrlr;
     236             : 
     237             : exit:
     238           0 :         spdk_vfio_user_release(vctrlr->dev);
     239           0 :         free(vctrlr);
     240           0 :         return NULL;
     241           0 : }
     242             : 
     243             : static int
     244           0 : nvme_vfio_ctrlr_scan(struct spdk_nvme_probe_ctx *probe_ctx,
     245             :                      bool direct_connect)
     246             : {
     247           0 :         int ret;
     248             : 
     249           0 :         if (probe_ctx->trid.trtype != SPDK_NVME_TRANSPORT_VFIOUSER) {
     250           0 :                 SPDK_ERRLOG("Can only use SPDK_NVME_TRANSPORT_VFIOUSER");
     251           0 :                 return -EINVAL;
     252             :         }
     253             : 
     254           0 :         ret = access(probe_ctx->trid.traddr, F_OK);
     255           0 :         if (ret != 0) {
     256           0 :                 SPDK_ERRLOG("Error to access file %s\n", probe_ctx->trid.traddr);
     257           0 :                 return ret;
     258             :         }
     259           0 :         SPDK_DEBUGLOG(nvme_vfio, "Scan controller : %s\n", probe_ctx->trid.traddr);
     260             : 
     261           0 :         return nvme_ctrlr_probe(&probe_ctx->trid, probe_ctx, NULL);
     262           0 : }
     263             : 
     264             : static int
     265           0 : nvme_vfio_ctrlr_enable(struct spdk_nvme_ctrlr *ctrlr)
     266             : {
     267           0 :         struct nvme_pcie_qpair *vadminq = nvme_pcie_qpair(ctrlr->adminq);
     268           0 :         union spdk_nvme_aqa_register aqa;
     269             : 
     270           0 :         if (nvme_vfio_ctrlr_set_asq(ctrlr, vadminq->cmd_bus_addr)) {
     271           0 :                 SPDK_ERRLOG("set_asq() failed\n");
     272           0 :                 return -EIO;
     273             :         }
     274             : 
     275           0 :         if (nvme_vfio_ctrlr_set_acq(ctrlr, vadminq->cpl_bus_addr)) {
     276           0 :                 SPDK_ERRLOG("set_acq() failed\n");
     277           0 :                 return -EIO;
     278             :         }
     279             : 
     280           0 :         aqa.raw = 0;
     281             :         /* acqs and asqs are 0-based. */
     282           0 :         aqa.bits.acqs = nvme_pcie_qpair(ctrlr->adminq)->num_entries - 1;
     283           0 :         aqa.bits.asqs = nvme_pcie_qpair(ctrlr->adminq)->num_entries - 1;
     284             : 
     285           0 :         if (nvme_vfio_ctrlr_set_aqa(ctrlr, &aqa)) {
     286           0 :                 SPDK_ERRLOG("set_aqa() failed\n");
     287           0 :                 return -EIO;
     288             :         }
     289             : 
     290           0 :         return 0;
     291           0 : }
     292             : 
     293             : static int
     294           0 : nvme_vfio_ctrlr_destruct(struct spdk_nvme_ctrlr *ctrlr)
     295             : {
     296           0 :         struct nvme_vfio_ctrlr *vctrlr = nvme_vfio_ctrlr(ctrlr);
     297             : 
     298           0 :         if (ctrlr->adminq) {
     299           0 :                 nvme_pcie_qpair_destroy(ctrlr->adminq);
     300           0 :         }
     301             : 
     302           0 :         nvme_ctrlr_destruct_finish(ctrlr);
     303             : 
     304           0 :         spdk_vfio_user_release(vctrlr->dev);
     305           0 :         free(vctrlr);
     306             : 
     307           0 :         return 0;
     308           0 : }
     309             : 
     310             : static  uint32_t
     311           0 : nvme_vfio_ctrlr_get_max_xfer_size(struct spdk_nvme_ctrlr *ctrlr)
     312             : {
     313           0 :         return NVME_MAX_XFER_SIZE;
     314             : }
     315             : 
     316             : static uint16_t
     317           0 : nvme_vfio_ctrlr_get_max_sges(struct spdk_nvme_ctrlr *ctrlr)
     318             : {
     319           0 :         return NVME_MAX_SGES;
     320             : }
     321             : 
     322             : const struct spdk_nvme_transport_ops vfio_ops = {
     323             :         .name = "VFIOUSER",
     324             :         .type = SPDK_NVME_TRANSPORT_VFIOUSER,
     325             :         .ctrlr_construct = nvme_vfio_ctrlr_construct,
     326             :         .ctrlr_scan = nvme_vfio_ctrlr_scan,
     327             :         .ctrlr_destruct = nvme_vfio_ctrlr_destruct,
     328             :         .ctrlr_enable = nvme_vfio_ctrlr_enable,
     329             : 
     330             :         .ctrlr_get_registers = nvme_vfio_ctrlr_get_registers,
     331             :         .ctrlr_set_reg_4 = nvme_vfio_ctrlr_set_reg_4,
     332             :         .ctrlr_set_reg_8 = nvme_vfio_ctrlr_set_reg_8,
     333             :         .ctrlr_get_reg_4 = nvme_vfio_ctrlr_get_reg_4,
     334             :         .ctrlr_get_reg_8 = nvme_vfio_ctrlr_get_reg_8,
     335             : 
     336             :         .ctrlr_get_max_xfer_size = nvme_vfio_ctrlr_get_max_xfer_size,
     337             :         .ctrlr_get_max_sges = nvme_vfio_ctrlr_get_max_sges,
     338             : 
     339             :         .ctrlr_create_io_qpair = nvme_pcie_ctrlr_create_io_qpair,
     340             :         .ctrlr_delete_io_qpair = nvme_pcie_ctrlr_delete_io_qpair,
     341             :         .ctrlr_connect_qpair = nvme_pcie_ctrlr_connect_qpair,
     342             :         .ctrlr_disconnect_qpair = nvme_pcie_ctrlr_disconnect_qpair,
     343             :         .admin_qpair_abort_aers = nvme_pcie_admin_qpair_abort_aers,
     344             : 
     345             :         .qpair_reset = nvme_pcie_qpair_reset,
     346             :         .qpair_abort_reqs = nvme_pcie_qpair_abort_reqs,
     347             :         .qpair_submit_request = nvme_pcie_qpair_submit_request,
     348             :         .qpair_process_completions = nvme_pcie_qpair_process_completions,
     349             : 
     350             :         .poll_group_create = nvme_pcie_poll_group_create,
     351             :         .poll_group_connect_qpair = nvme_pcie_poll_group_connect_qpair,
     352             :         .poll_group_disconnect_qpair = nvme_pcie_poll_group_disconnect_qpair,
     353             :         .poll_group_add = nvme_pcie_poll_group_add,
     354             :         .poll_group_remove = nvme_pcie_poll_group_remove,
     355             :         .poll_group_process_completions = nvme_pcie_poll_group_process_completions,
     356             :         .poll_group_destroy = nvme_pcie_poll_group_destroy,
     357             :         .poll_group_get_stats = nvme_pcie_poll_group_get_stats,
     358             :         .poll_group_free_stats = nvme_pcie_poll_group_free_stats
     359             : };
     360             : 
     361           0 : SPDK_NVME_TRANSPORT_REGISTER(vfio, &vfio_ops);
     362             : 
     363           0 : SPDK_LOG_REGISTER_COMPONENT(nvme_vfio)

Generated by: LCOV version 1.15