浅析错误:software IO TLB: coherent allocation failed for device

问题背景:i2c controller 在 probe 的时候,使用 dma_alloc_coherent 申请一块可持续使用的 dma 传输 buffer。平台使用 DRAM 大小为 6GB,未出现错误。

平台 DRAM 大小从 6GB 扩展到 8GB,dma_alloc_coherent 报错:"software IO TLB: coherent allocation failed for device "。

调查结果:

上图右侧部分是 arm 官方给出的物理内存类型以及地址分布,和实际工作中资料显示的格局是一样的,地址从下到上增长,ROM的起始地址是0x0000_0000。

根据实际工作中的经验来看,ROM+SRAM+Flash+Peripherals内存大小总和差不多是1GB,即0~0x3FFFFFFF。

当物理内存大小低于8GB,比如6GB,整个地址空间包括soc 地址空间(0x0~0x3FFFFFFF) + 片外地址空间(0x10000000~0x1BFFFFFFF)。

当物理内存高于或等于8GB,假设是8GB,整个地址空间包括soc 地址空间(0x0~0x3FFFFFFF) + 片外地址空间(0x10000000~0x23FFFFFFF)。

当设定dma_set_mask(&pdev->dev, DMA_BIT_MASK(33))时,dma_allocat_coherent()要求从CMA获取的地址是0x0~0x1FFFFFFFF[(0x1 << 33)-1](8GB-1)范围内。另CMA的区域范围总是在内存的高地址范围。
当物理内存大小低于8GB,比如6GB,整个地址空间包括soc 地址空间(0x0~0x3FFFFFFF) + 片外地址空间(0x10000000~0x1BFFFFFFF),CMA的区域范围总是在内存的高地址范围,从CMA获取的地址获取到的最大地址是0x1BFFFFFFF,就是在0x0~0x1FFFFFFFF范围内的,这个时候全部操作合理合法,不会报错;
而如果物理内存高于或等于8GB,假设是8GB,整个地址空间包括soc 地址空间(0x0~0x3FFFFFFF) + 片外地址空间(0x10000000~0x23FFFFFFF),CMA的区域范围又总是在内存的高地址范围,那么从CMA获取的地址就有可能高于0x1FFFFFFFF,这时就会导致swiotlb_tbl_map_single报错“swiotlb: coherent allocation failed”。

DRAM size=5GB, DRAM起点是0x40000000(1GB), 所以DRAM的范围是1GB ~ 7GB, dma_mask需要33bit;
DRAM size=8GB, DRAM起点是0x40000000 (1GB),所以DRAM的范围是1GB~ 9GB, dma mask需要34bit;
DRAM Size=8GB,就会导致在33bit mask之外的那段硬件没办法正常使用。
将mask设置为36bit,这样不管是33bit还是34bit都可以cover。

以上只是简单原因,很多细节还需要继续学习追查,比如CMA/DMA/slab/swio等内存管理的关系。

参考链接:

宋宝华:那些年你误会的Linux DMA(关于Linux DMA ZONE和API最透彻的一篇)

绝大多数的SoC目前都支持和使用CMA技术,并且多数情况下,DMA coherent APIs以CMA区域为申请的后端,这个时候,dma alloc coherent本质上用__alloc_from_contiguous()从CMA区域获取内存,申请出来的内存显然是物理连续的。这一点,在设备树dts里面就可以轻松配置,要么配置一个自己特定的cma区域,要么从“linux,cma-default”指定的缺省的CMA池子里面取内存

stackoverflow : dma_alloc_coherent failed on x86_64 but works on i686

After more investigation, I think you may have the same rootcause as me, just list it out for your reference. The CMA allocation will start from the highest memory blocks, so if you have more that 3G memory, the last physical memory will be above 0xFFFFFFFF, that means the CMA's base address is above 4GB, but dma_allocat_coherent() requires the address is below the mask [(0x1 << 32)-1] = 0xFFFFFFFF, if the alloacted dma end address is bigger than 0xFFFFFFFF, it will fallback to the swiotlb buffer and then you will see the error you described. Please see the below memory map, the last 2G is above 4GB memory space.

the appropriate solution is to specify the range or end address of the CMA region to be below 4GB.

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值