2013-01-31 101 views
6

我想分配一个大的DMA缓冲区,大小约40 MB。当我使用dma_alloc_coherent(),它失败,我所看到的是:分配一个大的DMA缓冲区

------------[ cut here ]------------ 
WARNING: at mm/page_alloc.c:2106 __alloc_pages_nodemask+0x1dc/0x788() 
Modules linked in: 
[<8004799c>] (unwind_backtrace+0x0/0xf8) from [<80078ae4>] (warn_slowpath_common+0x4c/0x64) 
[<80078ae4>] (warn_slowpath_common+0x4c/0x64) from [<80078b18>] (warn_slowpath_null+0x1c/0x24) 
[<80078b18>] (warn_slowpath_null+0x1c/0x24) from [<800dfbd0>] (__alloc_pages_nodemask+0x1dc/0x788) 
[<800dfbd0>] (__alloc_pages_nodemask+0x1dc/0x788) from [<8004a880>] (__dma_alloc+0xa4/0x2fc) 
[<8004a880>] (__dma_alloc+0xa4/0x2fc) from [<8004b0b4>] (dma_alloc_coherent+0x54/0x60) 
[<8004b0b4>] (dma_alloc_coherent+0x54/0x60) from [<803ced70>] (mxc_ipu_ioctl+0x270/0x3ec) 
[<803ced70>] (mxc_ipu_ioctl+0x270/0x3ec) from [<80123b78>] (do_vfs_ioctl+0x80/0x54c) 
[<80123b78>] (do_vfs_ioctl+0x80/0x54c) from [<8012407c>] (sys_ioctl+0x38/0x5c) 
[<8012407c>] (sys_ioctl+0x38/0x5c) from [<80041f80>] (ret_fast_syscall+0x0/0x30) 
---[ end trace 4e0c10ffc7ffc0d8 ]--- 

我试过不同的价值观,它看起来像dma_alloc_coherent()不能分配超过2^25字节(32 MB)。

如何分配如此大的DMA缓冲区?

+0

大DMA缓冲区是昂贵的。内存块必须是连续的物理内存(除非在某些SPARC系统中有用于I/O的MMU)并锁定(无法通过高优先级任务为页面错误分页)。典型的解决方法是使用多个DMA缓冲区并利用DMA链接(又名分散/聚集)。你真的有一个在一个块中传输40MB的I/O操作,还是这真的是一个操作的累积? – sawdust

+0

我正在使用的软件的用例需要大量的DMA缓冲区,以便通过专用硬件进行视频捕捉和图像处理。它可以通过使用几个较小的缓冲区来完成,但随着时间的推移,碎片化使释放和重新分配缓冲区成为问题。我需要的DMA缓冲区的大小和数量是固定的,所以我想在启动时分配一次内存,并在用户空间管理内存请求。 – miluz

+0

@miluz,你解决了这个问题吗?怎么样 ? – ransh

回答

6

系统启动后dma_alloc_coherent()对于大型分配不一定可靠。这很简单,因为不可移动的页面会快速填满您的物理内存,使大量连续范围变得罕见。这已经是一个长期以来的问题。

方便的是,最近的补丁集可能会帮助你,这是内核3.5中出现的连续内存分配器。如果你正在使用内核,那么你应该能够在你的内核命令行上通过cma=64M,并且内存将被保留(只有可移动的页面将被放置在那里)。当你随后要求你的40M分配时,它应该可靠地成功。 Simples!

欲了解更多信息,请参阅这篇文章LWN:

https://lwn.net/Articles/486301/

+0

在启动时分配内存对我来说足够好,所以我使用memblock_alloc_base()和memblock_remove()。据我了解,这些函数应该分配并使内存对内核不可见,并且它在物理地址中是连续的,因此很适合用于DMA。 – miluz

+0

我认为这应该可以工作,但它有点离谱。如果你想要一个你可以加载和卸载的内核模块,你也会遇到麻烦。 – jleahy