系统:linux 3.0
硬件平台:zynq
用dma_alloc_coherent 分配160k Bytes给dma用的物理内存总是失败。还是深究下其原因吧!为了方便跟踪函数走向,安装了ftrace进行跟踪。
1.ftrace的安装。
make menuconfig 选择 kernel hacking ---->Tracers:我把相关trace都打开了,比如跟踪中断时延,抢占时延
选定后然后进行保存。从新make即可。
2.ftrace的使用:
#我是通过char字符驱动的write函数里面分配内存。iq_wrtie--->dma_alloc_coherent
mount -t debugfs nodev /sys/kernel/debug #进行挂载
# 跟踪函数:
echo nop > /sys/kernel/debug/tracing/current_tracer
echo 0 > /sys/kernel/debug/tracing/tracing_on
echo function_graph > /sys/kernel/debug/tracing/current_tracer
echo iq_write > /sys/kernel/debug/tracing/set_graph_function
echo 1 > /sys/kernel/debug/tracing/tracing_on
#执行write函数
........
#抓数据
cat /sys/kernel/debug/tracing/trace > dma.txt
为了方便将数据折叠起来查看,使用function-graph-fold.vim(内核自带脚本)进行分析:
vim -S function-graph-fold.vim dma.txt
分析函数调用结果如下:
可见走的伙伴的快速分配路径,水位满足要求,从__rmqueue中分配出了物理内存。
我看ftrace并不能trace出所有的函数,只是看出物理内存分配确实没有问题。然后加些打印看看吧!
page = __dma_alloc_buffer(dev, size, gfp); //物理内存正常分配完成
printk(KERN_ERR "0:%s,__dma_alloc_buffer:%p\n",__func__,page);
if (!page)
return NULL;
printk(KERN_ERR "1:%s,arch_is_coherent():%p\n",__func__,arch_is_coherent());
if (!arch_is_coherent())
addr = __dma_alloc_remap(page, size, gfp, prot); //进行物理内存映射虚拟内存失败
else
addr = page_address(page);
printk(KERN_ERR "2:%s va_addr:%p\n",__func__,addr);
if (addr)
*handle = pfn_to_dma(dev, page_to_pfn(page));
通过打印(这里就不加了)得知是__dma_alloc_remap分配失败导致,继续跟进:
struct arm_vmregion *
arm_vmregion_alloc(struct arm_vmregion_head *head, size_t align,
size_t size, gfp_t gfp)
{
unsigned long start = head->vm_start, addr = head->vm_end;
unsigned long flags;
struct arm_vmregion *c, *new;
new = kmalloc(sizeof(struct arm_vmregion), gfp);
printk(KERN_ERR "1:%s new:%p\n\r",__func__,new);
if (!new)
goto out;
spin_lock_irqsave(&head->vm_lock, flags);
addr = rounddown(addr - size, align);
list_for_each_entry_reverse(c, &head->vm_list, vm_list) {
if (addr >= c->vm_end)
goto found;
addr = rounddown(c->vm_start - size, align);
if (addr < start){ //此处失败,因为用到的addr已经小于start的下限了
printk(KERN_ERR "2:%s addr:%p,start:%p \n\r",__func__,addr,start);
goto nospc;
}
可知是因为 分配出来的addr 已经小于start addr,导致虚拟地址分配失败了:
通过开机打印也可得知,dma的虚拟内存区域只有2M大小,看来不够用了:
最后更改memory.h中的DMA虚拟内存区域的大小为4M 分配成功:
#ifndef CONSISTENT_DMA_SIZE
#define CONSISTENT_DMA_SIZE SZ_4M
#endif
更多推荐
ftrace+printk 跟踪dma_alloc_coherent分配失败
发布评论