实现背景:
在虚机场景下,在virtio的寄存器模块中,按照现阶段的PVF+qid的寻址方式,考虑到虚机场景PVF按照最大2048个计算,现阶段有7个寄存器是queue级别的,每个寄存器是32bit,如果按照每个PVF可能对应的65个queue来计算,则总共消耗资源为2048657*32bit= 29,818,880bit,也就至少得1491个M20K的ram。如果后续pvf数量翻倍,那么资源会指数性的增加,这种方式无疑是无法接收的。 所以不能直接用上面的PVF+qid寻址方式,需要进行池化映射。 实际上,我们现在只需要支持最大2K个queue,所以queue级寄存器寻址方式需要进行一级池化,将pvf+qid映射成内部的2k深度的新的地址,就需要一套地址映射,地址管理的机制。
系统框图
将现在已有的virtio_reg_config模块里面的queue级寄存器全部提取出来,单独写一个模块(queue_level_reg_config)处理。此模块包含三个子模块,分别为queue_remap模块、addr_manage模块、reg_manege模块。 queue_remap模块:用于地址的映射,回收处理。 addr_manage模块:地址管理模块,分配产生池化后的地址。 reg_manege模块:7组queue级别的寄存器管理。
接口设计
queue_level_reg_config模块大约有5组配置接口,每一个接口的输入部分都会携带对应的PVF+qid的信息。其中一个是PVF级别的device status写1或者0接口,用于映射关系建立或者回收;其他几个是queue_size,avail_addr,desc_addr,used_addr这些要读写的寄存器接口。
实现过程
1*、queue_remap模块处理细节*
- 里面首先有一个地址映射关系表,索引是pvf_id。里面管理的数据内容是65个queue的映射后的地址,还有每个queue有效的标识位。位宽是6511+65=780 bit。这个索引关系表是为了方便地址资源回收、快速获取映射后的地址。如果后面每个pvf下qid更多,可以考虑将这个ram拆分成几个。映射关系ram大约如下图。*
- 写q级寄存器时,会向地址管理模块申请地(除了queue_msix_vector写0xffff,卸载驱动时会执行这个)
- 根据function num 判断那个是存储,哪个是网络,访问q_szie的时候,存储返回存储的q_zize默认值,网络返回网络的默认值。
- 地址回收功能。如果检测到某个pvf_id的device status写0,就要将这个pvf下所有地址进行回收,传给地址管理模块,进行地址分配。
5、addr_manage模块处理细节
此模块的主要功能就是新地址的生产和回收。 模块包含一个比较大的fifo,深度为2048,初始化的时候,写0到2047数值填满这个fifo。 如果有queue_remap模块过来的地址获取,则会从fifo里面提取一个数值出来,作为新的映射queue地址,并返回一个对应的有效指示信号,对应的就是vld+queue,这个值会写到queue_remap模块对应的请求ram中。
初始的时候,假如消耗掉了fifo里面的2048个缓存值,则当queue_remap模块继续过来索取新地址时,则不返回vld+queue。因为此时的索取为非法的。 当发生地址回收的时候,即对应的PVF的device status置位为0的时候,queue_remap模块会将ram中对应的PVF的vld+queue清零,并且,会将清零中对应有效的vld+queue,写到addr_manege模块的FIFO中,即为回收这些地址。后续如果有queue_remap模块来获取新的映射地址的时候,就会依次从此FIFO中读出一个值作为新的queue的映射地址。 综上所述,地址产生的来源有两个,一个是初始化的时候FIFO中分配的2k个地址,如果这些消耗完了,后续的地址就是靠第二种方式,即通过回收接口回收来获得。
配置写寄存器流程
配置写寄存器时,通过pvf索引映射表,找到对应q的vld是否有效。
如果有效,证明之前获取过一次地址,就直接用这个地址去写寄存器。
如果无效,就从地址管理模块获取一个地址,用这个地址写寄存器,并将地址回写到映射表里,并将vld写1
配置读寄存器
同样,配置读寄存器的时候,通过pvf索引映射表,查到对应q的vld是否有效,如果有效取出映射后的地址,读寄存器。如果非有效,证明之前未写过,或者地址非法,直接返回0
地址回收流程
系统模块框图
资源分析:
如果是在2k个pvf,每个pvf下最多33个q,最大支持4K个q的情况下
映射表需要的资源:204833*(11+1)=819200bit 也就是40个m20K*
寄存器地址映射后的需要的资源:4096324=524,288bit也就是大约26个m20k
如果是pvf+qid直接映射,则需要消耗资源大概是324*(2^(10+6))=8,388,608也就是410个m20k,*
相较于直接映射,可以减少300多个m20K
如果是在2k个pvf,每个pvf下最多65个q,最大支持2K个q的情况下
- queue_remap模块,映射表需要的资源:
204865(11+1)=1,597,440 bit,也就是80个m20K 。
- addr_manage模块,缓存映射后的queue地址的FIFO消耗的资源:
2048*11= 1,也就是1个m20K
(3)reg_manege模块,实际存放queue级别寄存器的资源消耗:
2048327=458,752 bit也就是大约23个m20k
总共需要80+1+23 = 104个M20k
如果是pvf+qid直接映射,则需要消耗资源大概是2048657*32bit= 29,818,880bit,也就至少得1491。
相较于直接映射,新池化的方案,可以减少1387多个m20K。
注意事项
需要注意模块之间的时序开销,尤其是queue_remap模块与addr_manege模块之间的地址获取和释放的过程中,所需要消耗的时钟周期,因此最好是在queueu_remap开头处加一个缓存的fifo,用于缓存所有的输入进来的PVF+qid读写寄存器的请求。只有当处理完一个完整的映射后,再进行下一个请求的响应。以免引起时序上的错误。