altera:
1. PCIe DMA应用屏蔽了复杂的PCIE协议,例如A10 pcie DMA控制器可以例化在IP核内部,DMA的寄存器端口被接到BAR0上,pc通过对BAR0地址的读写就可以操作DMA,BAR0-BAR1都是32位,组合起来成为1个64位的空间。BAR2用于寄存器访问,FPGA 端对Avalon MM的读写进行响应。
2.DMA读写都是通过PC主动配置FPGA的dma控制,由fpga的dma发起tlp mem读写请求。pc在内存中写好读或者写描述符,将描述符的物理地址写到BAR0寄存器中,告诉DMA去这个地址取描述符,按照描述符的指示搬移数据,搬移完成后,DMA回来写status =1,PC提前清除status,发送DMA后(最后一步操作写PTR),轮询最后一个status==1即可知道何时DMA结束。
3.dma例化时一般都有2种接口,avalon mm和avalon st。avalon mm可以后端自己写一个dma控制器,tlp包转mm由ip实现。avalon st由用户组tlp包和解tlp包。
xilinx:
1.7系列的FPGA提供了3种IP,封装层级依次复杂,分别是
7 Series Integrated Block for PCI Express:出来的是tlp包,只有三种,mem write/read,cpld。
AXI Memory Mapped To PCI Express,映射成了AXI MM。
DMA/Bridge Subsystem for PCI Express (PCIe),带DMA。
一般用XDMA的比较多,官方有linux下完善的驱动,和app例子,有一点linux c基础的都看得懂。QDMA更高级,是带循环链表的,在更高级器件上用得多。
XDMA也有ST和AXI 2种接口可选,example design中ST是直接回环的,AXI就是写BRAM。所有DMA流程都类似,都是先传block descriptor,让FPGA知道去哪儿取数据,取多长,或写数据,写多少由FPGA或者BD决定。FPGA对数据传输拆片,符合PCIE传输要求。传输结束后,中断或由PC轮询状态报给CPU,结束一次传输。
linux的驱动就更简单了,插入ko后,在dev下能看到多个xdma的节点,对h2c和c2h event就是简单的file读写操作,read是阻塞。中断也是read,区分不同的中断,读哪个中断就read哪个节点。对中断需要注意的是,需要保持req不变,否则驱动能响应中断,但不会传递给app,也就是read中断无返回。这里需要app去控制拉低req。
给一个常规的例子,接收到的数据,从流转为MM,ping pong写到DDR里,写满一定数量,比如8MB,产生中断通知pc,pc读寄存器知道当前是ping还是pong区,启动DMA读相应地址的数据。AXI smart connect或者interconnect相当好用,多主多从,跨时钟域访问每个AXI。
解TLP包和组TLP也不是特别麻烦,地址对齐和对TAG的处理最麻烦,尤其是保序问题,国产CPU有时候就很坑,不保序,读数据回来TAG是乱序的,好在intel的CPU还没有遇到这种问题。如果不是特别要求性能和资源,建议还是用xdma或者qdma,自己写的解包组包代码,要花很多时间扫BUG,很多偶现的问题,再带上业务非常麻烦。
主要接xlinx PCIE外包,win7/win10/linux下驱动和应用程序工业级开发。
如果觉得《altera/xlinx pcie dma应用》对你有帮助,请点赞、收藏,并留下你的观点哦!