Petalinux 2020.2(Zynq-7000)CMA分配故障求助
Zynq-7000开发板高分辨率显示CMA分配错误排查与解决
问题描述
自定义Zynq-7000开发板在使用1920x1080及更高分辨率时出现CMA分配失败,1024x768模式可正常运行。2560x1600分辨率下调试输出如下:
[12:09:34:466] xlnx-pl-disp amba_pl:xlnx_pl_disp: surface width(2560), height(1600) and bpp(24) [12:09:34:474] xlnx-pl-disp amba_pl:xlnx_pl_disp: bytes per line after alignment: 12288000 [12:09:34:480] xlnx-pl-disp amba_pl:xlnx_pl_disp: allocating 12288000 bytes with kzalloc()... [12:09:34:488] xlnx-pl-disp amba_pl:xlnx_pl_disp: OK [12:09:34:491] xlnx-pl-disp amba_pl:xlnx_pl_disp: init gem object... [12:09:34:497] xlnx-pl-disp amba_pl:xlnx_pl_disp: OK [12:09:34:500] xlnx-pl-disp amba_pl:xlnx_pl_disp: creating mmap offset... [12:09:34:505] xlnx-pl-disp amba_pl:xlnx_pl_disp: OK [12:09:34:508] xlnx-pl-disp amba_pl:xlnx_pl_disp: gem cma created with size 12288000 [12:09:34:514] xlnx-pl-disp amba_pl:xlnx_pl_disp: failed to allocate buffer with size 12288000 [12:09:34:522] xlnx-pl-disp amba_pl:xlnx_pl_disp: Failed to create cma gem object (12288000 bytes) [12:09:34:527] xlnx-pl-disp amba_pl:xlnx_pl_disp: drm_fb_helper_single_fb_probe() returns -12 [12:09:34:536] xlnx-pl-disp amba_pl:xlnx_pl_disp: Failed to set initial hw configuration. [12:09:34:541] xlnx-pl-disp amba_pl:xlnx_pl_disp: failed to initialize drm fb
经定位,问题出在drm_gem_cma_helper.c的以下代码行:
cma_obj->vaddr = dma_alloc_wc(drm->dev, size, &cma_obj->paddr,GFP_KERNEL | __GFP_NOWARN);
已尝试的调整(未解决):
- 内核配置中增大CMA大小(128MB → 256MB)
- 内核配置中增加CMA区域数量(7 → 20)
- 设备树中添加保留内存
- bootargs中添加
coherent_pool选项
排查方向与解决方案
1. 确认CMA区域的物理连续性
高分辨率帧缓冲需要连续物理内存块,即使总CMA大小足够,若内存被碎片化,也无法分配大连续块。可通过以下方式验证:
- 查看系统启动日志中CMA区域的分配信息,确认是否有足够大的连续空闲块
- 使用
cat /proc/meminfo查看CmaTotal、CmaFree和CmaUsed字段,重点关注空闲连续块的最大尺寸
2. 检查设备树中CMA的配置是否正确
确保设备树中CMA区域的定义覆盖了适合Zynq-7000的物理内存范围,且未与其他保留内存冲突。示例配置:
reserved-memory { #address-cells = <1>; #size-cells = <1>; ranges; cma@0x10000000 { compatible = "shared-dma-pool"; reg = <0x10000000 0x10000000>; /* 256MB */ reusable; status = "okay"; linux,cma-default; }; };
3. 调整dma_alloc_wc的分配标志
当前使用的GFP_KERNEL | __GFP_NOWARN可能无法应对内存碎片化,尝试添加__GFP_COMP标志(用于分配复合页,允许更大的连续块),修改后的代码:
cma_obj->vaddr = dma_alloc_wc(drm->dev, size, &cma_obj->paddr, GFP_KERNEL | __GFP_NOWARN | __GFP_COMP);
4. 验证Zynq-7000的内存控制器配置
确保PS端的内存控制器正确配置了DDR的大小和映射,避免因硬件层面的内存限制导致无法分配大缓冲区。可通过查看设备树中memory节点或启动日志中的内存检测信息确认。
5. 禁用其他占用大内存的模块
系统中若有其他模块(如视频编解码、DMA驱动)占用了大量连续内存,会影响CMA分配。可临时禁用这些模块,测试高分辨率显示是否正常,以排除内存竞争问题。
6. 调整内核内存分配策略
在内核配置中启用CONFIG_CMA_DEBUG,可以输出更详细的CMA分配日志,帮助定位碎片化问题。同时,可尝试启用CONFIG_CONTIG_ALLOC,增强连续内存分配的能力。
内容的提问来源于stack exchange,提问作者KotNitro
相关产品推荐
相关产品推荐

