您的位置:首页 > 其它

DMA分配内存,能用那些函数,那些不能用?why? 因为 DMA物理地址要连续

2012-04-20 21:35 375 查看
这两天有空重读了ldd的第8章内存管理,这本书是很好,但是有的内容不太实用,下面结合工作需要把常用的内容作下总结。

注意:下文提到的 j-one 平台内存是 128M。

1. ioremap :

ioremap 会按照页的大小调整映射size。另外,当地址没有页对齐的时候,ioremap会rounding down这个地址,也就是向下圆整地址,然后返回内存页的首地址+offset。下面是ldd的原文:

ioremap simulates an unaligned mapping by “rounding down” the address to be remapped and by returning an offset into the first remapped page.

2. kmalloc :

kmalloc 分配的内存物理地址连续。

1) 两个常用的flag:GFP_KERNEL和GFP_ATOMIC

2) size :

这个函数分配的内存必须是2的n次方。另外,这个函数分配的内存有大小限制。在arm平台上,最少分配32字节。最大依平台而异。比如:公司的j-one平台,最大能分配4M。

注:

下面具体分析下它的代码,

以 arm 平台为例,kmalloc 的实现在 include\linux\slab_def.h(但是不一定都在这个文件,在宏的控制下还有可能是其他两个文件 CONFIG_SLUB,CONFIG_SLOB)。其中控制分配buffer大小的代码在 #include <linux/kmalloc_sizes.h> 里面 。

由这个文件可知,KMALLOC_MAX_SIZE 就是最大 size 。下面是这个宏的定义:

#define KMALLOC_MAX_SIZE (1UL << KMALLOC_SHIFT_HIGH)

#define KMALLOC_SHIFT_HIGH ((MAX_ORDER + PAGE_SHIFT - 1) <= 25 ? \

(MAX_ORDER + PAGE_SHIFT - 1) : 25)

下面是在j-one平台上打出来的log

**********************************

KMALLOC_MAX_SIZE = 4194304

KMALLOC_SHIFT_HIGH = 22

MAX_ORDER = 11

PAGE_SHIFT = 12

failed to alloc 4194304+1

succeed to alloc 4194304

**********************************

3)物理地址与虚拟地址的关系:

在arm平台下kmalloc分配的内存的虚拟地址和物理地址只差一个偏移量。

注:

因为 kmalloc 最终还是调用 __get_free_pages,所以只要分析这个函数就好。见 page_alloc.c。

在该函数的最后一行也就是 page_alloc.c 1987行,page_address 这个宏将物理地址转换为虚拟地址。

arm平台的 page_address 参见 include/linux/mm.h 615行,

#define page_address(page) lowmem_page_address(page)

lowmem_page_address的实现参考同一个文件 590行,可以看到它是通过__va宏来做转换。

而__va可以参考 arch/arm/include/asm/memory.h, line 185。

#define __va(x) ((void *)__phys_to_virt((unsigned long)(x)))

在同一个文件的129行,可以看到

#define __phys_to_virt(x) ((x) - PHYS_OFFSET + PAGE_OFFSET)

所以确实如书中所说从物理地址到虚拟地址,只差一个偏移量。

3. 大块内存的分配:

1)alloc_bootmem:

该函数族要在内存管理子系统启动前调用,另外这个函数族分配的内存即使释放也不能由内存管理子系统回收。

2)另外一个方法是在启动参数中保留一块高地址内存。

4. vmalloc:

虚拟地址连续,物理地址不一定连续。

注意:kmalloc与vmalloc的区别是,前者分配的内存虚拟地址与物理地址之间只差一个偏移量,而vmalloc分配的内存则不是,另外vmalloc需要重建页表,从而vmalloc有性能问题。另外,和 ioremap 一样,vmalloc 要按照 page 对 size 参数圆整。

5. __get_free_pages:

该函数在分配大块内存时使用。注意:在j-one平台上最大只能分配10个page,所以它实际上和 kmalloc 一样,只能分配最大 4M 内存。

6. dma_alloc_writecombine 和 dma_alloc_coherent

如果需要分配关闭 cache 或者关闭 write buffer 的内存,可以使用这两个函数。

两者区别参见:arch\arm\include\asm\dma-mapping.h

dma_alloc_coherent:uncached, unbuffered

dma_alloc_writecombine:uncached, buffered
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐