Linux kernel 不跨越某些二次幂边界的dma映射

Linux kernel 不跨越某些二次幂边界的dma映射,linux-kernel,linux-device-driver,Linux Kernel,Linux Device Driver,我想为分配在我控制范围之外的内存缓冲区设置DMA映射。dma_map_single似乎是正确的API,但我的硬件有一个限制,即映射不能跨越两个边界的某些幂,例如1K。正在映射的缓冲区的大小始终小于边界值,但在其他方面是可变的。所以看起来DMA池可能无法工作,因为它们需要一个固定的大小,即使“分配”部分是我需要的 我是否应该继续使用dma_map_single并检查映射是否满足我的要求,如果不满足,则发布映射?这是否会导致可能返回相同的映射,从而导致无休止的搜索?如果是这样,我可以保留不合适的映射

我想为分配在我控制范围之外的内存缓冲区设置DMA映射。dma_map_single似乎是正确的API,但我的硬件有一个限制,即映射不能跨越两个边界的某些幂,例如1K。正在映射的缓冲区的大小始终小于边界值,但在其他方面是可变的。所以看起来DMA池可能无法工作,因为它们需要一个固定的大小,即使“分配”部分是我需要的

我是否应该继续使用dma_map_single并检查映射是否满足我的要求,如果不满足,则发布映射?这是否会导致可能返回相同的映射,从而导致无休止的搜索?如果是这样,我可以保留不合适的映射,直到找到合适的映射,然后一次性释放所有不合适的映射。然而,这些听起来并不是好主意

有人有其他/更好的想法吗


谢谢。

如果您不能保证通过的缓冲区符合您的标准,您可能需要分配一个辅助缓冲区,并在DMA之前向/从该缓冲区复制。在没有IOMMU或其他地址转换硬件(如经典x86、ARM等)的平台上,DMA映射操作实际上只是转换为物理地址。因此,如果您取消映射并使用相同的缓冲区重试,您将始终返回相同的DMA地址

在大多数(所有?)具有IOMMU的其他平台上,翻译仍然是在块>=页面大小上完成的。换句话说,如果您在一个具有4K页面的平台上,并且您在0xABCDExxx的缓冲区上进行DMA映射,您将始终获得一个类似0xFGHIJxxx的DMA地址,其中地址“xxx”的低位保持不变。(这是因为IOMMU的工作方式与普通MMU类似,只查找页面翻译,并保留低位12或其他任何位)

因此,在所有平台上的所有情况下,都不能使用DMA API来调整所传递的缓冲区的对齐方式。正如我所说的,我认为如果传递的缓冲区不满足对齐要求,唯一的选择是使用反弹缓冲区。DMA池API是分配这些反弹缓冲区的好方法——如果您有时需要更小的缓冲区,这是没有问题的;保留一些未使用的内存是可以的