我正在为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缓冲区永远不会超过几个字节,通过试图找出来制造麻烦是愚蠢的!
最佳答案 附带条件似乎是肯定的. (特别是“它比那更复杂”)
如果通过__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()来保持所有内容同步.我现在不会打扰 – 在驱动程序工作之后进行性能调整是一个更好的策略.
也可以看看:
> Does every dma_map_single call require a corresponding dma_unmap_single?
> Linux kernel device driver to DMA into kernel space