系统: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分配失败