最近在调试视频卡,虽然通了,但是公司CPU主频在300MHZ,对于采集D1格式图像显示到fb中并不是很流畅,分析原因,视频采集卡是PCI插槽,PCI的带宽没有问题,有一个想法,视频卡做DMA将采集到的图像放到内存中,CPU将图像再搬运到framebuffer中,这是视频采集的大体流程,在这个过程中最费CPU的是数据的搬运,在我自己写的小测试程序中就是循环的拷贝从videobuf到framebuffer。如果能将视频卡的DMA缓冲区直接映射到framebuffer中,就直接省掉了数据搬运的过程,视频卡采集数据和fb读取数据都是DMA操作,CPU不需要参与,这样视频的流畅度肯定能大幅度的提高,而且CPU占用率会很低。
实现这个想法需要做的工作是能实现视频卡DMA缓冲区和fb缓冲区的映射。说白了就是将做fb缓冲区的那段内存和视频卡DMA缓冲区的虚拟地址之间建立页表,这需要修改视频卡的mmap驱动实现,正好之前调视频卡DMA学习了LDD15章内存映射和DMA的后半部DMA,现在结合这个问题学习一下前半部内存映射。最终这个想法也实现了,这里记录一下,以备以后查看。
之前在刚学习PCI总线的时候,对于PCI设备的I/O内存的访问,内核采用的ioremap的方式,这也是将设备内存映射到内核虚拟地址,前面我也写过一篇总结ioremap的文章,这里主要介绍mmap的实现。
在现代unix系统中最吸引人的地方就是内存映射,对于驱动程序,内存映射提供了用户程序直接访问设备内存的能力,映射一个设备也就意味着将用户空间的一段内存与设备内存关联起来,无论何时访问这段地址范围实际是直接对设备的访问,这是LDD3上的一句话,这的确很令人心动!
在驱动程序中,最终传给底层mmap实现函数的参数是struct file和struct vm_area_struct,从系统调用mmap经过内核的处理,vm_area_struct代表着需要做映射的一段用户空间虚拟地址,驱动程序需要做的是为vma重新建立页表,以及填充vma->vm_ops操作。
mmap驱动实现中重新建立页表有2种方式,第一种方式调用remap_pfn_ra