一个简易的FPGA NVMe Host的参考设计

概 要

一直以来有不少开发人员采用FPGA来对接忆芯科技的NVMe固态硬盘,作为一些小型嵌入式设备的高速记录模块。FPGA灵活的可编程特点,可以方便实现各种高速、慢速接口的数据卸载和直连到忆芯科技NVMe固态硬盘的高速记录和回放。不过NVMe作为一种新型的存储接口市面上可直接参考的FPGA驱动的技术不是很常见,对于一些不太熟悉NVMe技术的开发者而言,要采用FPGA实现NVMe固态硬盘的读写也会比较费力。

因此,忆芯科技的研发团队实现了一个简易的FPGA NVMe Host的参考设计,旨在一定应用的范围内帮助有需求的开发者参考,快速利用FPGA来驱动NVMe固态硬盘实现特定的应用。

忆芯科技的FPGA NVMe Host的参考设计采用了软件驱动方式,具有相对简易而便于快速实现的特点。主要利用Xilinx FPGA原厂自带的PCIe IP核/总线/DRAM控制器(MIG)/Microblaze软核处理器或者硬核ARM(Zynq PS)处理器实现NVMe固态硬盘的高速存储。参考设计的主要特点如下:

  • 参考设计采用Xilinx 7系列FPGA实现NVMe Host针对STARBLAZE NVMe SSD设计实现
  • 参考设计包括FPGA SoC参考设计,嵌入式裸机(Bare Metal)参考程序
  • 参考设计主要实现NVMe Host协议驱动、GTP磁盘分区管理、exfat文件系统
  • 参考设计目标器件为Zynq 7z、Kentix 7、Vertix 7三个系列的参考设计
  • 参考设计嵌入式裸机参考目标处理器为ARMv7(Zynq 7z)和Microblaze(Kentix7 & Vertix7)
  • 参考设计创建1对CQ/SQ,队列深度支持256
  • 参考设计仅支持512b LBA和4096b内存page大小
  • 参考设计仅支持1 name space
  • 参考设计仅支持Identify、Flush、Write、Read命令
  • 参考设计仅支持GTP分区
  • 参考设计支持exfat文件系统,簇大小4k ~ 4M,推荐使用2M簇大小
  • 参考设计硬件开发板卡示例

    设计说明

    为便于理解参考设计,这里也顺便简单介绍下NVMe的基本原理。和SATA协议的交互模式不同,NVMe协议是基于内存模型通信交互方式。PCIe协议作为外设互联协议,把各种外设桥接到主机的内存空间,例如NVMe SSD设备上的内存被称为BAR(Base Address Register)空间被桥接到主机内存空间。NVMe SSD在自己的设备内存的BAR空间实现了各种寄存器便于主机操作和对设备控制。反过来,PCIe协议规定设备可以同样通过PCIe的桥接,直接读写访问主机的内存空间。例如NVMe SSD中具有能有够通过PCIe总线高速读写主机内存的DMA,PCIe设计中的这种DMA也被称为BUS DMA。

    NVMe协议是基于内存队列的通信协议。NVMe主机驱动在自己内存中构建Admin和IO队列。Admin和IO队列有SQ(Submission Queue)提交队列作为各种Admin和IO命令消息发送给设备执行,和CQ(Completion Queue)完成队列作为接收设备各种Admin和IO命令的完成消息。队列的有Tail尾和Head头来驱动,功能和FIFO的WPTR写指针和WPTR读指针类似。NVMe的Tail和Head称为DB(Door Bell)门铃,其地址存在于NVMe设备的内存BAR空间中。对于SQ 主机将命令消息写入主机内存的SQ中,然后更新NVMe设备DB中的SQ Tail,设备感知主机SQ Tail的更新,从而感知有新的命令消息下发,随即启动设备DMA,从主机内存的SQ取回命令消息后并更新对应的SQ Head表明已经取走对应的命令消息。

    命令消息包括各种命令的操作控制符表述。带数据的命令消息会有PRP(Physical Region Page)或者PRP指针,指向读写数据的位置。NVMe设备会根据命令消息执行命令,并同样通过DMA取回命令消息中的PRP和PRP指向的数据,通过实现主机内存的读写从而实现数据从主机到NVMe SSD或NVMe SSD到主机的数据读写。命令消息执行完成后,NVMe SSD设备会构造对应的完成消息同样也是通过DMA把完成消息写入位于主机内存的CQ中,并更新CQ Tail,同时发送PCIe中断(INTx/MSI/MSIX)通知主机命令消息执行完成。这个过程如图所示。

    NVNe 命令执行流程(引用自”An NVM Express Tutorial” Kevin Marks Dell, Inc. Flash Memory Summit 2013)

    因此忆芯FPGA NVMe host参考设计逻辑部分实现了一个有微处理器带PCIe RC的SoC系统。如下方框图所示,核心为Zynq PS ARM或Microblaze软核处理器。处理器除了自生的SRAM而外,需要大容量的DRAM作为PCIE共享内存。NVMe驱动和文件系统需要约20MB的共享内存。内存控制器采用Zynq PS侧的DRAM共享或者MIG生成。PCIe RC采用Xilinx “AXI Memory Mapped To PCI Express“ IP,置为RC模式。PCIe RC有一主一从两个AXI接口,实现PCIe设备到DDR共享内存以及CPU到PCIe的互通访问。其他设备为应用必要的外设,比如UART、SPI、以太网控制器等。

    FPGA设计框图

    FPGA CPU计算能力,特别是Microblaze软核计算能力较弱,需要最大化驱动SSD性能,因此本设计不采用操作系统,用裸机编程方式,最大化降低CPU调度开销。固件层面存储主要为NVMe驱动,GTP分区管理模块、EXFAT格式化模块、EXFAT文件系统模块,这几个模块封装在libnvme_storage静态库里面便于上层调用。

    固件主要模块说明

    由于本设计是软件驱动NVMe如何实现高性能的NVMe固态硬盘需要注意以下几点:

  • NVMe命令接口是以IO命令/完成方式和上层交互,每一个命令处理都会消耗CPU的计算和访存能力,因此操作的数据块越大,每个命令的效率也就越高,操作同样的数据消耗的CPU能力越小,本参考设计宜使用大块数据操作。在文件系统层面,采用1MB以上的簇大小能明显提升文件系统性能。同时这种大块数据访问对于固态硬盘也是非常友好的,可以明显减少写放大,减少掉速的比率。
  • 对于DRAM等耗时操作,特别对于Microblaze这种软核处理器访存代价是相当高的,因此需要Cache的助力。为提升效能,本设计宜使用写回(write back)的cache属性,并且在与NVMe固态硬盘交换数据的时候需要确保cache的一致性问题,时常需要程序显示flush或invalidate cacheline,确保CPU和NVMe固态硬盘看到的内存是一致的。
  • 对于NVMe固态硬盘的操作属于访存密集型应用。因此内存效率是第一位的。对于DRAM控制器,总线等在不影响FPGA实现的时序收敛情况下尽可能采用减少Latency IP配置设定。如果是Microblaze软核,也宜采用频率优先的配置设计,例如用最大级数流水线配置,关闭Branch Target Cache和MMU来尽量提升工作频率。
  • 忆芯科技FPGA NVMe host参考设计的实际测试性能如下。可以看到,测试采用忆芯STAR1200I S1200IYT1-T0M22T-P3 PLP M2 SSD性能,不管是Zynq还是K7/Z7 整体文件系统性能采用了上述策略后表现比较令人满意。特别是在V7上采用Microblaze 230MHz的软核能实现2G左右的文件读写能力,能够满足部分应用的需求。

    值得注意的是,K7和V7设计相比,同样的CPU配置下性能几乎有一倍的差距。这里并不是因为K7的PCIe是Gen2 x4,对比V7的PCIe Gen3 x4的区别。究其原因主要是由于 “AXI Memory Mapped To PCI Express“ IP,在桥接的Outstanding能力限制。K7的“AXI Memory Mapped To PCI Express“ IP只能支持Outstanding能力为4的传输,而V7支持Outstanding能力为8的传输。因此Z7的性能更是受到了这个Outstanding能力的制约。如果这里希望突破本参考设计的性能限制,下一步可以考虑采用原始PCIe IP,如“Xilinx 7 Series Gen3 Integrated Block for PCI Express” IP等,通过自行设计逻辑代码桥接到AXI总线上,突破“AXI Memory Mapped To PCI Express“ IP的限制。

    STAR1200I S1200IYT1-T0M22T-P3 性能测试

    此外忆芯科技FPGA NVMe host参考设计还设计了一系列串口演示命令,实现对忆芯固态硬盘上部署的文件系统的各种操作,如下图所示,受限于篇幅,这里也不多做赘述。

    文件操作演示:写文件/读文件/列表文件/文件属性查看/分区状态查看

    本文转载自: 北京忆芯科技有限公司

    最新文章

    最新文章