前言

  项目中需要通过驱动与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. hash 默认使用equal进行元素比较 防止元素重复

    hash 默认使用equal进行元素比较 防止元素重复

  2. Django 2.0 学习(08):Django 自动化测试

    编写我们的第一个测试 确定bug 幸运的是,在polls应用中存在一个小小的bug急需修复:无论Question的发布日期是最近(最后)的日期,还是将来很多天的日期,Question.was_publ ...

  3. BZOJ4866 Ynoi2017由乃的商场之旅(莫队)

    显然能重排为回文串相当于出现次数为奇数的字母不超过一个.考虑莫队,问题在于如何统计添加/删除一位的贡献.将各字母出现次数奇偶性看做二进制数,做一个前缀和一个后缀和.在右端添加一位时,更新区间的前缀.后 ...

  4. (转)java +libsvm 安装与测试:

    libsvm 用SVM实现简单线性分类  (转自:http://www.cnblogs.com/freedomshe/archive/2012/10/09/2717356.html) 0. 下载lib ...

  5. 解析Fetch实现请求数据

    一 序言 在 传统Ajax 时代,进行 API 等网络请求都是通过XMLHttpRequest或者封装后的框架进行网络请求,然而配置和调用方式非常混乱,对于刚入门的新手并不友好.今天我们介绍的Fetc ...

  6. IT英语累积

    JPA: Java Persistence API   一种持久化规范 Spring Data:一种用于简化数据库访问,支持云服务的开源框架 Spring Data JPA:是Spring Data的 ...

  7. 关于Javac编译器的那点事(一)

    Javac是什么? 它是一种编译器,将Java对人非常友好的语言,编译转化对所有机器都非常友好的语言,即:JVM能够识别的语言,也就是Java字节码.而Java字节码,说白了就是一连串二进制数字. J ...

  8. bzoj2733: [HNOI2012]永无乡(splay+启发式合并/线段树合并)

    这题之前写过线段树合并,今天复习Splay的时候想起这题,打算写一次Splay+启发式合并. 好爽!!! 写了长长的代码(其实也不长),只凭着下午的一点记忆(没背板子...),调了好久好久,过了样例, ...

  9. 【简单算法】37.Shuffle an Array

    题目: 打乱一个没有重复元素的数组. 示例: // 以数字集合 1, 2 和 3 初始化数组. ,,}; Solution solution = new Solution(nums); // 打乱数组 ...

  10. HDU 1715 大数java

    大菲波数 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submis ...