前言

  项目中需要通过驱动与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. [剑指Offer] 63.数据流中的中位数

    题目描述 如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值.如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值. c ...

  2. [剑指Offer] 50.数组中重复的数字

    题目描述 在一个长度为n的数组里的所有数字都在0到n-1的范围内. 数组中某些数字是重复的,但不知道有几个数字是重复的.也不知道每个数字重复几次.请找出数组中任意一个重复的数字. 例如,如果输入长度为 ...

  3. 【Python】Python time mktime()方法

    描述 Python time mktime() 函数执行与gmtime(), localtime()相反的操作,它接收struct_time对象作为参数,返回用秒数来表示时间的浮点数. 如果输入的值不 ...

  4. stm32f407启动文件分析

    ; Amount of memory (in bytes) allocated for Stack; Tailor this value to your application needs; < ...

  5. [LOJ2538] [PKUWC2018] Slay the Spire

    题目链接 LOJ:https://loj.ac/problem/2538 Solution 计数好题. 首先可以发现这题和期望没关系. 其次对于手上的一套牌,设我们有\(a\)张强化牌,那么: 如果\ ...

  6. BZOJ4897 [Thu Summer Camp2016]成绩单 【dp】

    题目链接 BZOJ4897 题解 发现我们付出的代价与区间长度无关,而与区间权值范围有关 离散化一下权值 我们设\(f[l][r][x][y]\)表示区间\([l,r]\)消到只剩权值在\([x,y] ...

  7. 洛谷 P2657 [SCOI2009]windy数 解题报告

    P2657 [SCOI2009]windy数 题目描述 \(\tt{windy}\)定义了一种\(\tt{windy}\)数.不含前导零且相邻两个数字之差至少为\(2\)的正整数被称为\(\tt{wi ...

  8. manacher 板子

    这个东西不难,不知道回文自动机咋样,掌握一种简单的写法就好了. 洛谷板子,欢迎来hack #include <cstdio> #include <cstring> int mi ...

  9. HDOJ.1800 Flying to the Mars(贪心+map)

    Flying to the Mars 点我挑战题目 题意分析 有n个人,每个人都有一定的等级,高等级的人可以教低等级的人骑扫帚,并且他们可以共用一个扫帚,问至少需要几个扫帚. 这道题与最少拦截系统有异 ...

  10. JS深度合并对象

    /** * 如果target(也就是FirstOBJ[key])存在, * 且是对象的话再去调用deepObjectMerge, * 否则就是FirstOBJ[key]里面没这个对象,需要与Secon ...