前言

  项目中需要通过驱动与fpga通讯,获取fpga往内存里写的数据。因为数据量比较大,需要驱动分配600多M的内存给fpga来写数据,且因为是与fpga通讯,需要连续的内存,还得是uncached的,因此打算采用dma接口dma_alloc_coherent来分配如此大的内存。然而,在分配的过程中遇到了一些问题,下面对这次的调试进行总结。

环境说明

  • soc: zc702(32bit arm + fpga)
  • ddr: 1g
  • linux kernel: 3.15.0

分配200M DMA空间失败

  原因分析:

  系统默认的DMA最大允许空间为128M,其他模块,如网卡驱动用去了一些,导致可使用的DMA空间低于128M了。要去分配200M,当然不够!

  解决方法:

  修改默认配置选项为CONFIG_CMA_SIZE_MBYTES=384,重新编译内核即可解决。当然,也可以通过给内核传参cma=384M,这样就不用重新编译内核了。

分配600M DMA空间失败

  当期望的dma分配为600M时,通过修改CMA_SIZE_MBYTES=700已经没用了,这会导致系统启动时报cma失败,进而导致系统其他模块dma申请都失败。CMA_SIZE_MBYTES=512(500是可以的)时报错信息如下:

cma: CMA: failed to reserve 512 MiB

原因分析:

没有这么大的连续空间

解决方法1:

找到没有这么大连续空间原因,毕竟CMA_SIZE_MBYTES已经为512M了

解决方法2:

如果方法1不能解决,那么只有通过另一种方式了,采用保留内存,然后再通过ioremap_nocache的方式申请这么大片保留的连续区域

在尝试方法1和方法2的过程中,又遇到了一些其他问题。

先说说方法2吧!保留内存很容易,在给内核传参时加上mem=256,那么就意味着我保留了768M内存,然而在ioremap时失败了,地址不够!!!这也很正常,毕竟内核的ioremap区域的地址才几十M,而我期望申请的是几百M!!!解决方法有,修改user/kernel 3G/1G的分配为1G/3G,这样内核的地址空间就够多了吧!经过验证,确实可以了。

再说说方法1,通过查看启动信息,发现dtb加载在0x20000000处,刚好是512M那里,这也就是导致了不连续的原因!通过修改uboot环境变量fdt_high(同理,如果用了ramdisk,那么可能也需要修改initrd_high的地址,后面就不再重复了)来修改dtb加载地址为0x28000000,成功启动。看来导致不连续的问题确实就是dtb导致的!那么将CMA_SIZE_MBYTES=512改为我们的目标CMA_SIZE_MBYTES=700 fdt_high=0x2c000000,是否可以呢?答案是no。错误信息如下:

cma: CMA: failed to reserve 700 MiB

这次我认为不是dtb的问题了,应该是linux kernel内存布局的限制!由于当前采用的user/kernel 3G/1G的分割,内核总共才1G的地址空间,且开启了CONFIG_HIGHMEM,而内核默认会保留240M(之前是128M,该问题后面细说)地址空间,低端内存总共才760M,而由于某些我暂时不知道的原因,限制了dma分配700M空间(可能是按某种比例划分导致的)!怎么解决呢???我的做法,第一步(当然,该方法不是解决该问题的关键),修改内核编译选项CONFIG_HIGHMEM,去掉highmem该功能,毕竟我们才1G内存,用那个选项会显得有点多余,还影响了性能!然而,新问题又出现了,这次是系统起来后,内存不是1G了,变成760M,再次分析得出,即使没有开启CONFIG_HIGHMEM,内核仍然会有240M地址空间作为保留,用于io remap等;第二步,采用方法2中的方法,修改user/kernel 3G/1G的分配为1G/3G。通过启动信息:

Memory: 416196K/1048576K available (5240K kernel code, 260K rwdata, 1616K rodata, 200K init, 301K bss, 632380K reserved)
Virtual kernel memory layout:
vector : 0xffff0000 - 0xffff1000 ( 4 kB)
fixmap : 0xfff00000 - 0xfffe0000 ( 896 kB)
vmalloc : 0x80800000 - 0xff000000 (2024 MB)
lowmem : 0x40000000 - 0x80000000 (1024 MB)
modules : 0x3f000000 - 0x40000000 ( 16 MB)
.text : 0x40008000 - 0x406ba454 (6858 kB)
.init : 0x406bb000 - 0x406ed380 ( 201 kB)
.data : 0x406ee000 - 0x4072f320 ( 261 kB)
.bss : 0x4072f32c - 0x4077a7a4 ( 302 kB)

可以看出,低端内存1G正常了,内存又回来了_,现在我将CMA_SIZE_MBYTES=700 fdt_high=0x30000000dma分配也正常了

240M的原因

Linux内核版本从3.2到3.3 默认的vmalloc size由128M 增大到了240M,3.4.0上的

修改Commit信息如下:

To accommodate all static mappings on machines withpossible highmem usage,

the default vmalloc area size is changed to 240 MB sothat VMALLOC_START

is no higher than 0xf0000000 by default.

总结

  本文提供了两种方式来解决期望DMA区域特别大的情况(几百M的情况),通过这次的bug调试,更加深入的理解了linux内存管理相关知识。突然想感叹下,好久没碰内核了,看来以后有时间就的补补!!!

关于cma扩展阅读

完!

2016年12月

增大dma的分配的更多相关文章

  1. 32.Linux-2440下的DMA驱动(详解)

    DMA(Direct Memory Access) 即直接存储器访问, DMA 传输方式无需 CPU 直接控制传输,通过硬件为 RAM .I/O 设备开辟一条直接传送数据的通路,能使 CPU 的效率大 ...

  2. 22、DMA驱动程序框架

    一.使用DMA的优点及DMA支持的请求源(请求源是启动DMA传输的事件,可以认为是触发.它可以是软件,也可以是中断,或者外部事件) 1.DMA优点是其进行数据传输时不需要CPU的干涉,可以大大提高CP ...

  3. Java NIO-09-零拷贝之 DMA

    DMA 的好处 在介绍DMA之前我想问大家:我们为什么要引入DMA,DMA对我们有什么好处那? 计算机系统中各种常用的数据输入/输出方法有查询方式(包括无条件及条件传送方式)和中断方式,这些方式适用于 ...

  4. 逃逸分析与栈、堆分配分析 escape_analysis

    小结: 1.当形参为 interface 类型时,在编译阶段编译器无法确定其具体的类型.因此会产生逃逸,最终分配到堆上. 2.The construction of a value doesn't d ...

  5. 栈 堆 stack heap 堆内存 栈内存 内存分配中的堆和栈 掌握堆内存的权柄就是返回的指针 栈是面向线程的而堆是面向进程的。 new/delete and malloc/ free 指针与内存模型

    小结: 1.栈内存 为什么快? Due to this nature, the process of storing and retrieving data from the stack is ver ...

  6. Memcached简介

    在Web服务开发中,服务端缓存是服务实现中所常常采用的一种提高服务性能的方法.其通过记录某部分计算结果来尝试避免再次执行得到该结果所需要的复杂计算,从而提高了服务的运行效率. 除了能够提高服务的运行效 ...

  7. PROC 文件系统调节参数介绍(netstat -us)

    转自:http://www.cnblogs.com/super-king/p/3296333.html /proc/net/* snmp文件 Ip: ip项 Forwarding        : 是 ...

  8. net_device 结构体分析

    /* * The DEVICE structure. * Actually, this whole structure is a big mistake. It mixes I/O * data wi ...

  9. Operating System Memory Management、Page Fault Exception、Cache Replacement Strategy Learning、LRU Algorithm

    目录 . 引言 . 页表 . 结构化内存管理 . 物理内存的管理 . SLAB分配器 . 处理器高速缓存和TLB控制 . 内存管理的概念 . 内存覆盖与内存交换 . 内存连续分配管理方式 . 内存非连 ...

随机推荐

  1. 第69天:jQuery入口函数

    一.jQuery入口函数 1.$(document).ready(function(){}); 2.$(function(){}); 二.事件处理程序  1.事件源 Js方式:document.get ...

  2. ismember matlab

    ismember 判断A中的元素在B中有没有出现 LIA = ismember(A,B) for arrays A and B returns an array of the same size as ...

  3. openstack之glance部署及操作

    由于时间关系简单的架构图就先不展示了.后续的更新会贴上... 部署glance 安装memcache服务 yum install memcached python-memcached systemct ...

  4. Luogu4899 IOI2018狼人(kruskal重构树+主席树)

    可以发现询问的即是“由起点开始‘只经过编号大于等于l的点’所形成的连通块”与“由终点开始‘只经过编号小于等于r的点’所形成的连通块”是否有交集.于是建出重构树,就可以知道每个询问的连通情况了.现在要知 ...

  5. linux查找文件目录及mysql卸载

    我们要卸载 mysql但是不知道其安装在哪里了,可以用  where +关键词 的方式查找,如上图 输入 whereis mysql 后,下面显示出了4个包含mysql的位置. ..... 查看安装m ...

  6. [POI2007] ZAP-Queries (莫比乌斯反演)

    [POI2007] ZAP-Queries 题目描述 Byteasar the Cryptographer works on breaking the code of BSA (Byteotian S ...

  7. mapper.xml配置读取不到

    通常我们在sping的配置文件中,扫描到mapper文件,但是mapper.xml找不到,此时解决办法就是在pom中添加下面代码: <resources> <resource> ...

  8. js获取当前页面的参数,带完善~~~

    let url = window.location.href; let id = url.slice(url.indexOf('?') + 4);

  9. SQL Server 代理(已禁用代理 XP)

    sp_configure 'show advanced options', 1; GO RECONFIGURE WITH OVERRIDE; GO sp_configure 'Agent XPs', ...

  10. JAVA有关命名规范

    包名:          xxxyyyzzz 全小写 类名/接口名:XxxYyyZzz 所有单词首字母大写,其他小写 方法名:       xxxYyyZzz第一个单词首字母小写,其他单词首字母大写 ...