我正在为SPI连接的LCD编写帧缓冲驱动程序。我使用kmalloc来分配缓冲区,这个缓冲区非常大 - 150KB。鉴于kmalloc分配缓冲区的方式,ksize会报告使用更多内存 - 大约256KB。
SPI spi_transfer结构接收指向tx和rx缓冲区的指针,这两个缓冲区都必须是DMA安全的。因为我希望tx缓冲区大约为16KB,我可以在kmalloced视频缓冲区中分配该缓冲区并且仍然是DMA安全吗?
这可以被认为是过早的优化,但视频缓冲区中有太多的空余空间,不使用它会感觉很糟糕!基本上,在以下之间分配的内存没有区别:
kmalloc(videosize)
和
kmalloc(PAGE_ALIGN(videosize) + txbufsize)
所以可以让kptr返回并执行:
txbuf = (u8 *)kptr + PAGE_ALIGN(videosize);
我知道“DMA安全”的部分要求是适当的对齐 - 我相信CPU高速缓存行大小... - 但是页面对齐不应该对此有用吗?
顺便说一句,我不确定tx和rx是否可以指向同一个地方。 spi.h标题也不清楚(实际上明确不清楚)。鉴于rx缓冲区永远不会超过几个字节,试图找出来制造麻烦是愚蠢的!
答案 0 :(得分:2)
答案似乎是肯定的。 (特别是“它比那更复杂”)
如果通过__get_free_page *()或通用内存分配器(kmalloc)获取内存,则可以使用这些例程返回的地址与该内存进行DMA交换。基本的含义是kmalloc中的页面对齐缓冲区,甚至跨越多个页面,将是DMA安全的,因为底层物理内存保证是连续的,并且页面对齐的缓冲区保证在缓存行边界上。
一个附带条件是设备是否能够驱动整个总线宽度(例如:ISA)。因此,内存的物理地址必须在设备的dma_mask内。
另一个是缓存一致性要求。它们以高速缓存行宽度的粒度运行。为了防止两个单独的内存区域共享一个高速缓存行,dma的内存必须完全在高速缓存行边界上开始,并且恰好在一个高速缓存上结束。鉴于这可能不为人所知,建议(DMA API文档)仅映射在页面边界上开始和结束的虚拟区域(因为这些区域也保证是如上所述的高速缓存行边界)。
在这种情况下,DMA驱动程序可以使用dma_alloc_coherent()分配DMA容量空间,以保证DMA区域不可缓存。由于这可能很昂贵,因此也存在流式传输方法 - 对于单向通信 - 其中一致性仅限于写入时的高速缓存刷新。在先前分配的缓冲区上使用dma_map_single()。
在我的情况下,将tx和rx缓冲区传递给没有dma_map_single的spi_sync很好 - spi例程将为我完成。我可以使用dma_map_single以及unmap或dma_sync_single_for_cpu()来保持所有内容同步。我现在不会打扰 - 在驱动程序工作之后调整是一个更好的策略。
另见: