kmalloc中的缓冲区也是DMA安全缓冲区吗?

car*_*one 5 linux-device-driver linux-kernel dma

我正在为SPI连接的LCD编写帧缓冲驱动程序。我使用kmalloc分配缓冲区,该缓冲区很大-150KB。给定kmalloc分配缓冲区的方式,ksize报告使用更多内存的方式-大约256KB。

SPI spi_transfer结构采用指向tx和rx缓冲区的指针,这两个缓冲区都必须是DMA安全的。由于我希望tx缓冲区大约为16KB,我可以在kmalloced视频缓冲区中分配该缓冲区,并且仍然是DMA安全的吗?

这可以被认为是过早的优化,但是视频缓冲区中有太多的备用空间,很难使用它!基本上,分配的内存之间没有区别:

kmalloc(videosize)
Run Code Online (Sandbox Code Playgroud)

kmalloc(PAGE_ALIGN(videosize) + txbufsize)
Run Code Online (Sandbox Code Playgroud)

因此,可以将kptr返回并执行以下操作:

txbuf = (u8 *)kptr + PAGE_ALIGN(videosize);
Run Code Online (Sandbox Code Playgroud)

我知道“ DMA安全”的部分要求是适当的对齐方式-与我认为的CPU缓存行大小...-但是页面对齐是否可以这样做?

顺便说一句,我不确定tx和rx是否可以指向同一位置。spi.h标头也不清楚(实际上明显不清楚)。鉴于rx缓冲区永远不会超过几个字节,因此尝试找出麻烦来是很愚蠢的!

car*_*one 4

答案似乎是肯定的,但附带条件。(具体来说“比这更复杂”)

如果您通过 __get_free_page*() 或通用内存分配器 (kmalloc) 获取内存,那么您可以使用从这些例程返回的地址与该内存进行 DMA 传输。潜在的含义是 kmalloc 中的页面对齐缓冲区(即使跨越多个页面)也将是 DMA 安全的,因为底层物理内存保证是连续的,并且页面对齐缓冲区保证位于缓存行边界上。

一个附带条件是该设备是否能够驱动整个总线宽度(例如:ISA)。因此,内存的物理地址必须在设备的 dma_mask 范围内。

另一个是缓存一致性要求。这些以高速缓存行宽度的粒度进行操作。为了防止两个独立的内存区域共享一个高速缓存行,DMA 的内存必须恰好在高速缓存行边界上开始并恰好在高速缓存行边界上结束。鉴于这一点可能未知,建议(DMA API 文档)仅映射在页面边界上开始和结束的虚拟区域(因为这些也保证是如上所述的缓存行边界)。

在这种情况下,DMA 驱动程序可以使用 dma_alloc_coherent() 分配可 DMA 的空间,以保证 DMA 区域不可缓存。由于这可能很昂贵,因此还存在一种流方法(用于单向通信),其中一致性仅限于写入时的缓存刷新。在先前分配的缓冲区上使用 dma_map_single()。

就我而言,在没有 dma_map_single 的情况下将 tx 和 rx 缓冲区传递给 spi_sync 很好 - spi 例程会为我做这件事。我可以自己使用 dma_map_single 以及 unmap 或 dma_sync_single_for_cpu() 来保持所有内容同步。不过,我现在不会打扰 -驱动程序工作后调整性能是更好的策略。

也可以看看: