文章目录

    • 1、dma_alloc_coherent用法
    • 2、问题
    • 3、解决方法
      • 方法一,走CMA空间配置
        • 3.1 内核配置``CONFIG_CMA``
        • 3.2 修改cma起始地址
        • 3.3 设置cma空间(大小和地址等)
          • 3.3.1 内核配置
          • 3.3.2 cmdline配置
          • 3.3.3 dts配置
      • 方法二,修改内核代码
    • 参考

1、dma_alloc_coherent用法

通过dma_alloc_coherent接口可以申请连续的大块内存。

dma_addr_t dma_handle;
cpu_addr = dma_alloc_coherent(dev, size, &dma_handle, gfp);

入参:

dev:	``struct device *``,可设为NULL
size:  想要申请的内存长度,单位为bytes
gfp:   分配内存时的标志位,如GFP_KERNEL等,在此不多介绍

出参

cpu_addr:   内存虚拟其实地址
dma_handle: 实际物理地址

2、问题

使用这个接口最大只能申请到4M的内存,申请超过4M时,报swiotlb buffer is full (sz: 16777216 bytes)错误。

3、解决方法

方法一,走CMA空间配置

3.1 内核配置CONFIG_CMA

在内核配置CONFIG_CMA=y,dma分配默认会走cma,空间会大点。
cat /proc/meminfo |grep Cma 可查看设备上cma空间大小。

3.2 修改cma起始地址

按照3.1设置后,有时仍然报swiotlb错误.
参考一个大佬的回答,总结如下:
检查内核打印,给cma分配的地址是否在4G以上,dma_allocat_coherent() 要求地址低于掩码[(0x1 << 32)-1] = 0xFFFFFFFF。如果地址大于这个,它将回退到 swiotlb 缓冲区。
因此需要指定cma空间分配的地址,方法见3.3

3.3 设置cma空间(大小和地址等)

3.3.1 内核配置

配置CONFIG_CMA=y后,cma空间应默认为64M.
如果需要修改,先配置CONFIG_DMA_CMA=y打开DMA Contiguous Memory Allocator, 再配置CONFIG_CMA_SIZE_MBYTES大小就行。
相关配置:

CONFIG_DMA_CMA
CONFIG_CMA_AREAS配置 CMA 分配器区域数
CONFIG_CMA_SIZE_MBYTES配置 CMA 的大小
CONFIG_CMA_SIZE_SEL_MBYTES按 MB 配置 CMA 区域大小
CONFIG_CMA_SIZE_SEL_PERCENTAGE按物理内存的百分比配置 CMA 区域大小
CONFIG_CMA_SIZE_SEL_MIN优先选择最小的 CMA 体积
CONFIG_CMA_SIZE_SEL_MAX优先选择最大的 CMA 体积
CONFIG_CMA_ALIGNMENT CMA对齐大小

优点:
配置简单便捷。
缺点:
不能指定cma区域的地址。

3.3.2 cmdline配置

可通过cmdline配置cma空间属性。用法说明:

cma=nn[MG]@[start[MG][-end[MG]]]
            [ARM,X86,KNL]
            Sets the size of kernel global memory area for
            contiguous memory allocations and optionally the
            placement constraint by the physical address range of
            memory allocations. A value of 0 disables CMA
            altogether. For more information, see
            include/linux/dma-contiguous.h

例如:

cma=128M                    /* 设置一个128M的cma空间 */
cma=128M@0x8000000          /* 设置一个128M的cma空间并指定起始地址为0x8000000 */
cma=256M@0-4G               /* 在0-4G范围内设置一个256M的cma空间 */

cma=256M@0-4G 可解决上述dma_allocat_coherent要求地址在0~4G范围内的问题。
优点:
可配置大小,也可指定地址。
可通过uboot传参,也可内核指定CMDLINE。

3.3.3 dts配置

在dts中添加cma节点,可指定cma大小和空间。

方法二,修改内核代码

4M这个限制是本身应该是分的普通内存的限制, 例如把配置加一个CONFIG_FORCE_MAX_ZONEORDER=16把最大限制改成128M也能解决。

  23 /* Free memory management - zoned buddy allocator.  */
  24 #ifndef CONFIG_FORCE_MAX_ZONEORDER
  25 #define MAX_ORDER 11
  26 #else
  27 #define MAX_ORDER CONFIG_FORCE_MAX_ZONEORDER
  28 #endif
  29 #define MAX_ORDER_NR_PAGES (1 << (MAX_ORDER - 1))
"./include/linux/mmzone.h"    

参考

For the problem when using swiotlb
dma_alloc_coherent failed on x86_64 but works on i686

更多推荐

dma_alloc_coherent 申请内存用法和问题总结