作者: 宋立新
Email:[email protected]
现象:最近好几个模块的同事都反应驱动中调用:dma_alloc_writecombine 会失败!
研究:首先重现该问题, 在 nand 驱动的 probe 函数: pxa3xx_nand_probe 中调用 dma_alloc_writecombine:
测试代码:
#if 1
{
int i;
for (i=0; i < 1000; i++) {
buf_len = 0x100000;
info->data_desc = (struct pxa_dma_desc*)dma_alloc_writecombine(&pdev->dev,
buf_len, &info->data_desc_addr, GFP_KERNEL);
printk("i:%d, phy:0x%lx, virt:0x%lx/n", i, info->data_desc_addr, info->data_desc);
if (!info->data_desc)
while(1) {}
}
}
#endif
得到串口打印:
i:0, phy:0xa7300000, virt:0xff600000
i:1, phy:0xa7400000, virt:0xff700000
i:2, phy:0xa7500000, virt:0xff800000
i:3, phy:0xa7600000, virt:0xff900000
i:4, phy:0xa7700000, virt:0xffa00000
i:5, phy:0xa7800000, virt:0xffb00000
i:6, phy:0xa7900000, virt:0xffc00000
i:7, phy:0xa7a00000, virt:0xffd00000
i:8, phy:0xffffffff, virt:0x0
从输出看来,应该是虚拟地址不够用了, 导致出错。
仔细分析一下目前系统的虚存占用情况:
目前虚拟地址空间的占用:
物理内存: 0xc0000000-0xcfffffff (256M)
IO:
0xf2000000 32M
0xf4000000 1M
0xf6000000 2M
0xf8000000 1M
0xfa000000 1M
0xfa500000 1M
0xfe000000 1M
0xff000000 1M
向量表及保留:0xfffe0000-0xffffffff (这个是内核使用的)
虚拟内存应该还有很大的空间可用。
再去分析 dma_alloc_writecombine 的代码,
dma_alloc_writecombine ->__dma_alloc 中用如下代码分配虚拟地址:
c = vm_region_alloc(&consistent_head, size,gfp & ~(__GFP_DMA | __GFP_HIGHMEM));
原来 DMA 从 consistent_head 分配虚拟地址空间. 再去看看consistent_head的定义:
static struct vm_region consistent_head = {
.vm_list = LIST_HEAD_INIT(consistent_head.vm_list),
.vm_start = CONSISTENT_BASE,
.vm_end = CONSISTENT_END,
};
#define CONSISTENT_END (0xffe00000)
#define CONSISTENT_BASE (CONSISTENT_END - CONSISTENT_DMA_SIZE)
#define CONSISTENT_DMA_SIZE 8 * 1024 * 1024
真相大白! consistent_head 一共只有 8M 空间!
根据目前的虚拟地址空间分布,可以简单修改CONSISTENT_DMA_SIZE 为: 8M->12M 可将虚拟地址空间增大一些
如果需要更大,则需要修改CONSISTENT_END, 目前可以修改到 0xf2000000, 然后将
CONSISTENT_DMA_SIZE 改到 32M.