nvme hardware queue 初始化流程

主要步骤

To setup and initialize I/O Submission Queues and I/O Completion Queues for use, host software follows these steps:

  1. Configures the Admin Submission and Completion Queues by initializing the Admin Queue Attributes (AQA), Admin Submission Queue Base Address (ASQ), and Admin Completion Queue Base Address (ACQ) registers appropriately;
  2. Submits a Set Features command with the Number of Queues attribute to request the desired number of I/O Submission Queues and I/O Completion Queues. The completion queue entry for this Set Features command indicates the number of I/O Submission Queues and I/O Completion Queues allocated by the controller;
  3. Determines the maximum number of entries supported per queue (CAP.MQES) and whether the queues are required to be physically contiguous (CAP.CQR);
  4. Creates the desired I/O Completion Queues within the limitations of the number allocated by the controller and the queue attributes supported (maximum entries and physically contiguous requirements) by using the Create I/O Completion Queue command; and
  5. Creates the desired I/O Submission Queues within the limitations of the number allocated by the controller and the queue attributes supported (maximum entries and physically contiguous requirements) by using the Create I/O Submission Queue command.

At the setup and initialized and may be used to complete I/O commands.

参考代码

spdk/examples/nvme/perf/perf.c


static void
attach_cb(void *cb_ctx, const struct spdk_nvme_transport_id *trid,
          struct spdk_nvme_ctrlr *ctrlr, const struct spdk_nvme_ctrlr_opts *opts)
{
        struct trid_entry       *trid_entry = cb_ctx;
        struct spdk_pci_addr    pci_addr;
        struct spdk_pci_device  *pci_dev;
        struct spdk_pci_id      pci_id;

        g_controllers_found++;
        if (trid->trtype != SPDK_NVME_TRANSPORT_PCIE) {
                printf("Attached to NVMe over Fabrics controller at %s:%s: %s\n",
                       trid->traddr, trid->trsvcid,
                       trid->subnqn);
        } else {
                if (spdk_pci_addr_parse(&pci_addr, trid->traddr)) {
                        return;
                }

                pci_dev = spdk_nvme_ctrlr_get_pci_device(ctrlr);
                if (!pci_dev) {
                        return;
                }

                pci_id = spdk_pci_device_get_id(pci_dev);

                printf("Attached to NVMe Controller at %s [%04x:%04x]\n",
                       trid->traddr,
                       pci_id.vendor_id, pci_id.device_id);
        }

        register_ctrlr(ctrlr, trid_entry);
}

static int
register_controllers(void)
{
        struct trid_entry *trid_entry;

        printf("Initializing NVMe Controllers\n");

        TAILQ_FOREACH(trid_entry, &g_trid_list, tailq) {
                if (spdk_nvme_probe(&trid_entry->trid, trid_entry, probe_cb, attach_cb, NULL) != 0) {
                        fprintf(stderr, "spdk_nvme_probe() failed for transport address ‘%s‘\n",
                                trid_entry->trid.traddr);
                        return -1;
                }
        }

        return 0;
}

/*
 * TODO: If a controller has multiple namespaces, they could all use the same queue.
 *  For now, give each namespace/thread combination its own queue.
 */
static int
nvme_init_ns_worker_ctx(struct ns_worker_ctx *ns_ctx)
{
        struct spdk_nvme_io_qpair_opts opts;
        struct ns_entry *entry = ns_ctx->entry;
    int i = 0;

        spdk_nvme_ctrlr_get_default_io_qpair_opts(entry->u.nvme.ctrlr, &opts, sizeof(opts));
        if (opts.io_queue_requests < entry->num_io_requests) {
                opts.io_queue_requests = entry->num_io_requests;
        }

    ns_ctx->u.nvme.qpair = calloc(g_num_pair, sizeof(struct spdk_nvme_qpair*));
    for (i = 0; i < g_num_pair; i++) {
        ns_ctx->u.nvme.qpair[i] = spdk_nvme_ctrlr_alloc_io_qpair(entry->u.nvme.ctrlr, &opts,
                       sizeof(opts));
        if (!ns_ctx->u.nvme.qpair[i]) {
            printf("ERROR: spdk_nvme_ctrlr_alloc_io_qpair failed\n");
            return -1;
        }
    }

        return 0;
}

参考代码

原文地址:https://blog.51cto.com/xiamachao/2387265

时间: 2024-11-06 07:07:36

nvme hardware queue 初始化流程的相关文章

深入理解nvme hardware queue pair

hardware queue pair是什么 hardware queue pair是我们理解nvme/spdk的牛鼻子,只有深入理解才可能把nvme用好. 从nvme控制器寄存器的角度看 顾名思义,就是一些硬件寄存器组成的队列. 空队列 满队列 问题:能否并发入队.出队?不行 submission hardware queue entry 每个entry如下表所示: 入队: host software 提交命令到tail entry, 通过操作submission hardware queue

SylixOS CAN总线初始化流程解析

概述 本文档是在AT91SAM9X25平台上进行SylixOS CAN总线驱动开发时,对CAN总线初始化流程的分析. 适用于正在学习CAN总线开发的技术工程师. 技术实现 CAN总线的初始化流程可以分成两个部分: 一部分是CAN总线通道资源初始化,主要工作是对通道相关的管脚和中断以及总线编程时需要的时钟等资源的初始化:另一部分是CAN总线的硬件初始化,主要工作是对总线的波特率的设置.接收和发送数据邮箱(相当于缓存区)的初始化以及接收中断和错误中断的使能. CAN总线通道资源初始化 在AT91SA

SpringMVC源码剖析(三)- DispatcherServlet的初始化流程

在我们第一次学Servlet编程,学Java Web的时候,还没有那么多框架.我们开发一个简单的功能要做的事情很简单,就是继承HttpServlet,根据需要重写一下doGet,doPost方法,跳转到我们定义好的jsp页面.Servlet类编写完之后在web.xml里注册这个Servlet类. 除此之外,没有其他了.我们启动web服务器,在浏览器中输入地址,就可以看到浏览器上输出我们写好的页面.为了更好的理解上面这个过程,你需要学习关于Servlet生命周期的三个阶段,就是所谓的“init-s

Android技术20:Android的初始化流程

Android系统是如何启动的呢,应用程序是如何启动.下面简要介绍下初始化流程. 1.Android系统的初始化 1.1Android系统会首先启动Linux基础系统,然后引导加载Linux内核并启动初始化进程Init Linux Kernel---->Init(pid=1) 1.2启动守护进程Daemons 启动Usb守护进程,管理USB连接 启动Android Debug Bridge守护进程管理ADB连接 启动Debuggerd Debug守护进程 启动无线接口守护进程管理无线通信 1.3

Android 6.0 SIM卡初始化流程

本文主要讲述Android 6.0 SIM卡初始化流程,这个过程也涉及到UICC框架的初始化,UICC(Universal Integrated Circuit Card)的架构图如下: /** * This class is responsible for keeping all knowledge about * Universal Integrated Circuit Card (UICC), also know as SIM's, * in the system. It is also

【开源】OSharp3.3框架解说系列(7.1):初始化流程概述

本文已同步到系列目录:OSharp快速开发框架解说系列 框架初始化 相对于OSharp 3.0,3.3版本最大的更新,就是从框架级别定义了初始化流程,对初始化功能进行了抽象与封装,不依赖于第三方实现,第三方实现仅作为可替换的服务实现方案存在. 例如,依赖注入功能中,接口与其实现类的映射配置,对象容器的构建,对象的解析获取,都将通过框架定义的API来完成,而Autofac,仅作为这些功能的实现方存在,如果不想使用Autofac,则可以很方便的切换成别的IoC组件. 具体的初始化功能是怎样抽象与定义

Raid1源代码分析--初始化流程

初始化流程代码量比较少,也比较简单.主要是run函数.(我阅读的代码的linux内核版本是2.6.32.61) 四.初始化流程分析 run函数顾名思义,很简单这就是在RAID1开始运行时调用,进行一些初始化的操作.主要是对RAID1中的conf进行初始化.run函数在md.c的do_md_run中被调用.   run函数的具体流程 0.传入参数mddev就是指RAID1所处的MD设备. 1.  定义相关变量. 1.1  定义conf指针,类型为raid1_private_data_s,是raid

深入浅出高性能服务发现、配置框架Nacos系列 3: 服务发现:Nacos客户端初始化流程

上一章节,我们从全局了解了一下Nacos项目的模块架构,做到了心中有数,现在,我们去逐步去挖掘里面的代码细节,很多人在学习开源的时候,无从下手,代码那么多,从哪个地方开始看呢?我们可以从一个接口开始入手,这个接口是你使用过的,知道它大概做什么事,有体感的,大家还记得第一章时,我们写的HelloWorld吗,对,就从里面的接口开始剥洋葱. 这个是Nacos的github代码地址,开始之前先start关注一下,加上watch,后续Nacos的邮件列表也会通知到你,可以关注到Nacos的最新实时消息,

关于Flutter初始化流程,我必须告诉你的是...

1. 引言 最近在做性能优化的时候发现,在混合栈开发中,第一次启动Flutter页面的耗时总会是第二次启动Flutter页面耗时的两倍左右,这样给人感觉很不好.分析发现第一次启动Flutter页面会做一些初始化工作,借此,我梳理了下Flutter的初始化流程. 2. Flutter初始化时序 Flutter初始化主要分四部分,FlutterMain初始化.FlutterNativeView初始化.FlutterView初始化和Flutter Bundle初始化.我们先看下Flutter初始化的时