三、virtio_blk在FPGA中的实现架构
如图3所示,为viriot_blk控制器在FPGA内部实现的架构框图。图3中pcie部分为FPGA内部设计模块,作为host驱动与virtio_blk控制器的桥接模块,这里不做详细说明,本文重点关注virtio_blk控制器部分。
在图3中,virtio_blk控制器主要的功能就是作为后端设备,与前端进行交互,将host发起的一系列读写操作进行组织转发到远端磁盘系统,并且将host对远端磁盘的读写数据进行搬移等。virtio_blk控制器包含virtio_csr、virtio_adaptor、fetch_index、fetch_ring、fetch_desc、fetch_pkt、mate_builder、slot_adaptor、data_parser、updata_pkt等主要模块。
图 3 virtio_blk在FPGA中的结构示意图
如图3所示,这里介绍每个模块实现的功能和他们之间的交互流程等。
(1)virtio_csr:virtio寄存器模块,主要缓存PF或者VF对应的queue的公共配置寄存器和特定配置寄存器等,作为host侧driver与FPGA侧device之间寄存器交互用的,是整个virtio的控制通道,例如virtio的初始化,notify、中断,还有每个虚拟queue对应的index、ring环、描述符等对应的起始地址等,还包含一些统计调试寄存器等。有关控制面的寄存器交互,都是通过此模块来处理和连接的。
(2)virtio_adaptor:数据通道合并选择模块,其主要功能是将多路的dma读写请求,做通道选择。当virtio_blk控制器向host发起dma读写请求时,此模块就是多合一,将多条请求通道采用RR轮询的方式,合并成一个通道与host交互。当host响应virtio_blk控制器的读请求时,就是将返回的响应数据一分多,按照先前记录的读请求顺序,正确的返回到对应的通道中。因此此模块也有维序功能。
(3)fetch_index:获取host侧虚拟queue的共享ring环中的head index。触发此动作的来源,为host侧进行notify通知机制。只有当收到对应queue的notify信号,此模块才会开始去取host侧对应queue的index,并且将取到的head index送到下一级fetch_ring模块中。
(4)fetch_ring:获取host侧虚拟queue的共享ring环中对应数组值,此数组的索引为head index,里面内容为此index对应的第一个描述符链表的索引。触发此模块工作的来源,为fetch_index模块输入过来的index相关信息,最后从host获取到数组值,即第一个描述符的位置索引,传递到下一个fetch_desc模块。
(5)fetch_desc:获取host侧虚拟queue中当前head index对应的描述符。模块是通过fetch_ring模块传输过来的数组信息来驱动的,数组里面带有描述符链表中第一个描述符的标号,根据此标号可以找到此index对应的第一个描述符,然后此描述符里面又包含下一个描述符的标号,由此标号找到链表的下一个描述符,这第二个描述符也包含第三个描述符位置的标号,以此类推,可以找到此index对应的所有描述符链表。将同一个虚拟queue的同一个index对应的完整的描述符组成的链表,按照前后获取的顺序排列,一次性完整的送到mate_builder模块处理。
(6)mate_builder:组包头,并将同一个queue的同一个index对应的描述符链表进行分类传输。此模块是通过fetch_desc模块传输过来的描述符链表信息来驱动的。当收到一个完成的描述符链表后,将会根据描述符里面的标志位来分成两部分。第一部分为只写host的描述符,这部分描述符组成一个包头,传输到fetch_pkt模块。第二部分为只读host的描述符,同样也传输给fetch_pkt模块,不过这部分描述符需要会被fetch_pkt模块消耗掉。
(7)fetch_pkt:获取host侧只读数据,并组包。此模块是通过mate_builder模块传输过来的两部分描述符信息来驱动的。此模块会将只读host的描述符进行拆解分析,根据描述符里面的地址+数据长度来获取到host侧的数据。然后把这些数据和只写host描述符组成的包头进行拼接合并,组成一个包头+数据的存储包,传输到slot_adaptor模块。
(8)slot_adaptor:virtio_blk控制器对接远端模块的输入输出模块。此模块主要功能有两部分,第一部分功能是将fetch_pkt模块输入过来的存储包加标号,以显示此包为哪各PF或者VF的虚拟queue的存储包,至此输出的存储包为一个完整的包了。第二部分功能就是接收远端磁盘返回的完成包,并解析出来对应的PF或者VF的queue的信息,并将解析的结果和对应的完成包信息送到data_parser模块处理。
(9)data_parser:解析来自slot_adaptor模块的完成包。此模块是通过slot_adaptor模块传输过来的完成包等信息来驱动的。当接收到完成包,第一步就是将包头和数据部分剥离。第二步解析出包头里面携带的只写host描述符等信息,第三部把这些解析信息和剥离后剩下的数据部分一起送到下级模块。
(10)updata_pkt:上传数据、更新host侧used_index和发起中断等。此模块是通过data_parser模块传输过来的解析包等信息来驱动的。当收到解析信息和数据时,会根据解析信息里面的只写host描述符,将数据分段写到host侧内存。写完数据后就开始更新host侧共享ring环的used_index,并且向host发起一个中断指令,通知host有新的数据更新。
至此,从virtio_csr模块初始化配置开始,fetch_index模块接收host的notify通知,到现在updata_pkt模块发出中断指令通知host读写已完成,virtio_blk控制器完成一个IO完整的转发工作了。