最近使用xilinx的zynq,需要完成FPGA和ARM的AXI协议通讯,通过增加linux内核启动参数mem=1008M保留了顶部的16M内存空间用来读写数据,FPGA以DMA方式来访问这个内存空间,接下来要完成的就是给这16M的内存空间编写platform_device的驱动程序。
现在讲期间碰到的问题总结一下:
1)DMA:
什么是DMA:就是没有CPU的情况下,由DMA控制器完成内存RAM和其他部分的数据交互,可以写RAM,也可以读RAM。具体方式就是设定DMAC的源地址和目标地址,以及DMA方式,然后写入传输的字节数就可以启动DMA数据传输了。CPU设置完后就不用管数据的传输了。
DMA牵涉到cache,因为CPU为了提高和RAM的交互性能,会把RAM中的部分数据放到cache,这样CPU从cache读要比从RAM读快多了,CPU会根据需要更新cache或则flush。
但是DMA方式因为没有CPU的参与,会导致cache中的新数据还没有flush到RAM,RAM中的旧数据就被读走了;或者RAM中的数据已经被DMAC更新了,但是CPU还是从cache读取了旧数据。因此,当使用DMA方式时,DMA读写RAM的同时要通知CPU,具体方式如下:
1.DMA把RAM数据拷贝出去之前,先把cache数据flush;
2.DMA把数据拷贝到RAM后,使无效RAM中的这段地址。
在linux中,操作RAM都是对内核虚拟地址而言。
可以参考http://blog.csdn.net/linweig/article/details/5327002以及http://www.linuxidc.com/Linux/2011-09/42076.htm
invalidate_dcache_range flush_dcache_range 在mm/cache.c文件下。
/***********下段的结论依赖于具体的硬件,可以参看*****************
*************ioremap和ioremap_nocache函数的实现是否一致***********
但是,DDR作为外设时不需要cache操作,因为DDR物理地址是通过ioremap到内核虚拟地址的,相当于读写外设的寄存器,即便FPGA以DMA方式读写DDR外设,但是ioremap后得到的地址指针也能够读取到正确的数据。
也就是说,ioremap后,对指针的操作直接影响DDR外设,不会经过cache。
***********************************************************************************/
2)read和write使用copy_to_user、copy_from_user还是ioread8、iowrite8
为什么会有ioread8、iowrite8等函数?
主要目的是防止编译器优化,导致读写指令重新排序。
在驱动里面,提供ioread8等函数的目的是不让直接使用ioremap返回的指针,因为对于外设寄存器ioremap得到的指针操作时,必须要避免由于CPU或编译器不恰当的优化而改变预期的I/O动作(引自LDD3)。
RAM的访问可以通过多个方法进行优化:高速缓存保存数值、重新排序读写指令。
而外设的驱动程序要确保不适用告诉缓存,访问寄存器时不发生读或写指令的重新排序。
显然,DDR外设不受读写指令重新排序的干扰,因为它并不是真正意义的硬件外设。
但是高速缓存呢?如何解决,ioremap是否自身已经把这个问题解决了呢?
查看
3)是否使用mmap替代read和write,是否可以提高性能
其实最后的解决方案就是使用了mmap,保留了部分RAM用作数据存储区。