队列管理模块是整个NVMe Host控制器的核心模块,该模块实现了提交队列与完成队列的管理,多队列请求的仲裁判决等功能。队列管理模块中含有数据选择单元、SQ、CQ、和仲裁器等模块。其中Admin SQ与IO SQ的内部结构一致,包含状态机、BRAM、Tail REG和Head REG。Admin CQ与IO CQ的内部结构一致,包含状态机、Tail REG和Head REG。
队列管理模块框图如图1所示。

图1 队列管理模块框图
在NVMe协议中,使用队列来传输、缓存和处理命令条目,以实现Host端和NVMe SSD端之间的通信。在CPU上运行NVMe软件协议栈,其Host端生成提交命令的速度远大于NVMe SSD的执行速度,同时由于CPU的指令是顺序执行的,需要通过中断来通知CPU去处理完成信息。因此,通过增加提交队列和完成队列的深度可以提高系统的传输性能。
设计中可以利用FPGA的并行处理能力来加速NVMe Host端的控制流程。相较于软件协议栈,通过硬件电路生成提交命令的速度更快,并且能够通过并行操作去实时检查返回的完成信息,从而避免了采用中断来通知CPU去处理完成信息而造成延迟较大的问题。本设计主要针对顺序读写场景进行了资源方面的优化。考虑到在顺序读写情况下,传输性能与队列深度的大小无关,且硬件逻辑生成NVMe命令的速度要远大于软件协议栈生成NVMe命令的速度,因此通过增加提交队列和完成队列的深度来提高系统的传输性能的方法不再可行,本设计将提交队列深度设置为NVMe SSD一次突发读取的数据量大小,这样在保证性能的前提下,可以尽可能的减少资源的消耗。此外,取消了完成队列缓存的设计,对完成信息的解析工作通过组合逻辑电路对其进行实时检测,而不用通过中断来通知NVMe Host检查,从而可以提高NVMe命令的执行效率,并节省了大量的存储资源。
提交队列内部由一个双端口RAM、两个寄存器和一个状态机构成。其中,提交队列分为Admin提交队列和I/O提交队列,分别用于管理Admin命令和I/O命令。虽然这两个队列针对的命令条目不同,但其内部结构相同。因此,通过采用相同的设计来实现两个队列,以提高代码的复用性和可维护性。双端口RAM使用BRAM资源实现,包括两个128位宽、深度可配置的端口,用于实现NVMe命令的缓存。四个控制寄存器用于监测队列状态,包括Head指针和Tail指针。Head指针指向队列中下一个被执行的命令的位置,Tail指针指向队列中下一个空位置,新产生的命令条目总是被写入Tail所指向的位置。当同一个队列的Head指针等于Tail指针加1时,表示队列为满;当Head指针等于Tail指针时,表示队列为空。该模块中的状态机用来实现门铃寄存器信息更新的流程控制工作。队列管理状态机的跳转图如图2所示。

图2 队列管理状态机跳转图
各状态说明如下:
IDLE:空闲状态,该状态为模块上电后的初始化状态,该状态下检测到s_axis_entry_valid信号有效时,表示有提交命令传输至队列管理模块,状态跳转至RD_SQ_REG状态,否则维持当前IDLE状态。
RD_SQ_REG:读提交队列寄存器状态,该状态下读取提交队列中的cmd_cnt寄存器,cmd_cnt寄存器负责记录队列中缓存的命令数,即SQ Head指针与SQ Tail指针之差,当cmd_cnt寄存器的值大于10时向仲裁器发起更新门铃寄存器请求,这里设置为10主要是考虑到减少NVMe Host控制器和NVMe SSD之间的数据交互次数,让其通过突发传输一次读取多条命令,来达到提升系统性能的效果,同时,为了解决长时间没有接收到新的提交命令使得小于10条命令无法发送的情况,添加了超时机制,当计时计数器达到一定值时,不再等待cmd_cnt满足条件,直接跳转至SC_REQ状态,否则维持当前状态。
SC_REQ:仲裁请求状态,该状态下将sq_req信号置为高电平来向仲裁器发起仲裁请求,若接收到仲裁授权,状态跳转至SEND状态,否则维持当前状态。
SEND:发送状态,该状态下向接口转换模块发送当前的队列信息,接口转换模块将内部信号转换为AXI4接口信号,通过访问PCIe的BAR空间来实现对NVMe SSD门铃寄存器的更新,等待返回应答信号,状态跳转至IDLE状态。
对相关视频感兴趣者,请移步B站搜用户名: 专注与守望
或wx: zzbxidian
|