阿呆实战NVMe之九

原创内容,转载请注明:  [http://www.ssdfans.com]  谢谢!

提要

 

本系列文章,旨在带你开发一个NVMe SSD控制器的前端协议逻辑,只不过是在QEMU虚拟机环境中。万事开头难,前面我们花了8篇文章来写NVMe在QEMU中的初始化,一方面说明初始化的重要和琐碎,另一方面也暴露了阿呆的水平不够,要是真完全掌握的人必然是高屋建瓴,言简意赅。阿呆学艺不精,只能一个函数一个函数来带你逛NVMe的集市了。

 

本篇我们来看看NVMe设备在QEMU的Doorbell如何实现,探探蛋蛋说过的大宝,阿呆改名成贴心暖男——大白。

 

NVMe寄存器配置流程

 

前面我们讲到,NVMe初始化的时候注册了MMIO,如下,两个函数nvme_mmio_read, nvme_mmio_write就是来做BAR空间的读写,对BAR空间的读写最终都会调用这兄弟俩。

1 /* NVMe is Little Endian. */
2 n->mmio_index = cpu_register_io_memory(nvme_mmio_read, nvme_mmio_write,
3     n,  DEVICE_LITTLE_ENDIAN);

再来看看NVMe的BAR空间地址分配,如下,看得出来,前面0x1000之前都是寄存器空间。自然,每当Host来读写这些地址的时候,其实就是在读写对应的寄存器。0x1000之后是每个SQ,CQ队列的大白(门铃,doorbell)的地盘。

 1 /* NVMe Controller Registers */
 2 enum {
 3     NVME_CAP       = 0x0000, /* Controller Capabilities, 64bit */
 4 // 各种寄存器
 5     NVME_CMD_SS    = 0x0F00, /* Command Set Specific*/
 6     NVME_SQ0TDBL   = 0x1000, /* SQ 0 Tail Doorbell, 32bit (Admin) */
 7     NVME_CQ0HDBL   = 0x1004, /* CQ 0 Head Doorbell, 32bit (Admin)*/
 8     NVME_SQ1TDBL   = 0x1008, /* SQ 1 Tail Doorbell, 32bit */
 9     NVME_CQ1HDBL   = 0x100c, /* CQ 1 Head Doorbell, 32bit */
10 
11     NVME_SQMAXTDBL = (NVME_SQ0TDBL + 8 * NVME_MAX_QID),
12     NVME_CQMAXHDBL = (NVME_CQ0HDBL + 8 * NVME_MAX_QID)
13 };

对于每个寄存器,QEMU都有对应变量,所以调用前面的都写函数读写寄存器都会反映到这些内部变量,例如:

1 case NVME_ASQ:
2     nvme_cntrl_write_config(nvme_dev, NVME_ASQ, val, DWORD);
3     *((uint32_t *) &nvme_dev->sq[ASQ_ID].dma_addr) = val;
4     break;

 

大白是干啥的?

 

大白

 

如果调用nvme_mmio_write写SQ的大白地址段,大白就开始工作了。大白工作的办公室名字叫process_doorbell,参数如下。每次门铃一响,大白就通过地址addr推算出按的是哪个队列的门铃,其中偶数号的是SQ,Host给device的命令队列,奇数号的是CQ,device发给host的响应队列。

1 static void process_doorbell(NVMEState *nvme_dev, target_phys_addr_t addr,
2     uint32_t val)

 

先转一下蛋蛋总结的SQ和CQ的作用:

  1. SQ用以Host发命令,CQ用以SSD回命令完成状态
  2. SQ/CQ在Host 内存中;
  3. 两种类型的SQ/CQ:Admin和I/O,前者发送Admin命令,后者发送I/O命令;
  4. 系统中只能有一对Admin SQ/CQ,但可以有很多对I/O SQ/CQ;
  5. I/O SQ与CQ可以是一对一的关系,也可以是一对多的关系;
  6. I/O SQ是可以赋予不同优先级的;
  7. I/O SQ/CQ深度可达64K,Admin SQ/CQ深达4K;
  8. I/O SQ/CQ的广度和深度都可以灵活配置;
  9. 每条命令大小是64字节,每条命令完成状态是16字节;
  10. 不要过河拆桥。

 

再来看蛋蛋对大白的定义:“doorbell,DB,就是用来记录了一个SQ或者CQ的Head和Tail。每个SQ或者CQ,都有两个对应的DB: Head DB和Tail DB。DB是在SSD端的寄存器,记录SQ和CQ的头和尾巴的位置。”

 

一句话太简单,阿呆继续友情转载一大段:

 

“那么,DB在命令处理流程中起了什么作用呢?

 

首先,如前所示,它记住了SQ和CQ的头和尾。对SQ来说,SSD是消费者,它直接和队列的头打交道,很清楚SQ的头在哪里,所以SQ head DB由SSD自己维护;但它不知道队伍有多长,尾巴在哪,后面还有多少命令等待执行,相反,Host知道,所以SQ Tail DB由Host来更新。SSD结合SQ的头和尾,就知道还有多少命令在SQ中等待执行了。对CQ来说,SSD是生产者,它很清楚CQ的尾巴在哪里,所以CQ Tail DB由自己更新,但是SSD不知道Host处理了多少条命令完成信息,需要Host告知,因此CQ Head DB由Host更新。SSD根据CQ的头和尾,就知道CQ能不能以及能接受多少命令完成信息。

 

DB的另外一个作用,就是通知作用:Host更新SQ Tail DB的同时,也是在告知SSD有新的命令需要处理;Host更新CQ Head DB的同时,也是在告知SSD,你返回的命令完成状态信息我已经处理,同时表示谢意。”

 

现实中的大白

 

看得出来,SQ的大白有消息,就意味着新的命令来了,赶快记下来,找人开工。CQ的大白有消息,就意味着上次汇报之后,老板已经知道SSD最近干了什么活,所以需要把这些记录清理掉,以后不用汇报了。

 

我们来到基层实际看看上面的理论是怎么操作的。首先看CQ队列,只看核心的代码:

1 uint16_t new_head = val & 0xffff;
2 queue_id = (addr - NVME_CQ0HDBL) / QUEUE_BASE_ADDRESS_WIDTH;
3 nvme_dev->cq[queue_id].head = new_head;
4 
5 if (nvme_dev->cq[queue_id].tail != nvme_dev->cq[queue_id].head) {
6     /* more completion entries, submit interrupt */
7     isr_notify(nvme_dev, &nvme_dev->cq[queue_id]);
8 }

 

可以看出来,通过大白的地址算出来队列编号queue_id,接着更新CQ的head到上级领导写下来的位置,意味着下次从这个新的位置开始汇报工作。最后,再检查一下,是不是还有没处理完的CQ,如果有,就触发中断,申请上级领导在百忙之中抽出时间听取最新工作汇报。

 

接下来,看看SQ队列的大白要干些啥子事情。计算队列编号和拿寄存器数据和CQ一样,只不过寄存器内容变成了队列的尾巴。因为写从tail往后填,读从head开始拿,所以领导往SQ尾巴填命令,SSD就得知道尾巴填到哪里了。大白发现上级领导有新的工作任务发下来了,就设置定时器,5微秒之后让负责的人执行。可见分工很严密啊,大白忠心耿耿,所以只负责传达命令。

 1 uint16_t new_tail = val & 0xffff;
 2 queue_id = (addr - NVME_SQ0TDBL) / QUEUE_BASE_ADDRESS_WIDTH;
 3 nvme_dev->sq[queue_id].tail = new_tail;
 4 
 5 deadline = qemu_get_clock_ns(vm_clock) + 5000;
 6 
 7 if (nvme_dev->sq_processing_timer_target == 0) {
 8     qemu_mod_timer(nvme_dev->sq_processing_timer, deadline);
 9     nvme_dev->sq_processing_timer_target = deadline;
10 }

 

大白的活是干完了,但是设置了定时器,到时候活得有人干啊,下文我们就来看看到底是谁在处理SQ。

 

引用

https://github.com/nvmeqemu

分类目录 SSD, 技术文章.
扫一扫二维码或者微信搜索公众号ssdfans关注(添加朋友->点最下面的公众号->搜索ssdfans),可以经常看到SSD技术和产业的文章(SSD Fans只推送干货)。
ssdfans微信群介绍
技术讨论群 覆盖2000多位中国和世界华人圈SSD以及存储技术精英
固件、软件、测试群 固件、软件和测试技术讨论
异构计算群 讨论人工智能和GPU、FPGA、CPU异构计算
ASIC-FPGA群 芯片和FPGA硬件技术讨论群
闪存器件群 NAND、3D XPoint等固态存储介质技术讨论
企业级 企业级SSD、企业级存储
销售群 全国SSD供应商都在这里,砍砍价,会比某东便宜20%
工作求职群 存储行业换工作,发招聘,要关注各大公司招聘信息,赶快来
高管群 各大SSD相关存储公司高管和创始人、投资人

想加入这些群,请微信扫描下面二维码,或搜索nanoarchplus,加阿呆为微信好友,介绍你的昵称-单位-职务,注明群名,拉你进群。SSD业界需要什么帮助,也可以找阿呆聊。