dma_map_single dma_map_sg理解


What memory is DMA'able?
========================

The first piece of information you must know is what kernel memory can
be used with the DMA mapping facilities.  There has been an unwritten
set of rules regarding this, and this text is an attempt to finally
write them down.

If you acquired your memory via the page allocator
(i.e. __get_free_page*()) or the generic memory allocators
(i.e. kmalloc() or kmem_cache_alloc()) then you may DMA to/from
that memory using the addresses returned from those routines.

This means specifically that you may _not_ use the memory/addresses
returned from vmalloc() for DMA.  It is possible to DMA to the
_underlying_ memory mapped into a vmalloc() area, but this requires
walking page tables to get the physical addresses, and then
translating each of those pages back to a kernel address using
something like __va().  [ EDIT: Update this when we integrate
Gerd Knorr's generic code which does this. ]

This rule also means that you may use neither kernel image addresses
(items in data/text/bss segments), nor module image addresses, nor
stack addresses for DMA.  These could all be mapped somewhere entirely
different than the rest of physical memory.  Even if those classes of
memory could physically work with DMA, you'd need to ensure the I/O
buffers were cacheline-aligned.  Without that, you'd see cacheline
sharing problems (data corruption) on CPUs with DMA-incoherent caches.
(The CPU could write to one word, DMA would write to a different one
in the same cache line, and one of them could be overwritten.)

Also, this means that you cannot take the return of a kmap()
call and DMA to/from that.  This is similar to vmalloc().

以下为测试代码

  1. 测试 dma_map_single + vmalloc
char *buf_ptr = NULL;
dma_addr_t dma_addr = 0;
buf_ptr = vmalloc(1024*100);
dma_addr = dma_map_single(dev,buf_ptr_1024*100,DMA_BIDIRECTIONAL);
if (dma_mapping_error(dev,dma_addr)) {
	dev_err(dev,"mapping buffer failed\n");
}

测试发现 dma_map_single 若 mapping 的 vmalloc申请的buf_ptr,可以正常返回iova地址,且 dma_mapping_error 没有报错。 但是通过打印 buf_ptr 地址的内容发现并没有被写入。即无法使用dma_map_single 直接 mapping 的 vmalloc申请的地址

  1. 测试 dma_map_single + kmalloc
char *buf_ptr = NULL;
dma_addr_t dma_addr = 0;
buf_ptr = kmalloc(1024*100);
dma_addr = dma_map_single(dev,buf_ptr_1024*100,DMA_BIDIRECTIONAL);
if (dma_mapping_error(dev,dma_addr)) {
   dev_err(dev,"mapping buffer failed\n");
}

测试发现 dma_map_single 若 mapping 的 kmalloc申请的buf_ptr,可以正常返回iova地址,且 dma_mapping_error 没有报错。 但是通过打印 buf_ptr 地址的内容发现有内容被写入。即可以使用dma_map_single 直接 mapping 的 kmalloc 申请的地址

原因是:
kmalloc() 分配的虚拟地址范围在内核空间的「直接内存映射区」。
按字节为单位虚拟内存,一般用于分配小块内存,释放内存对应于 kfree ,可以分配连续的物理内存。函数原型在 <linux/kmalloc.h> 中声明,一般情况下在驱动程序中都是调用 kmalloc() 来给数据结构分配内存。

vmalloc 分配的虚拟地址区间,位于 vmalloc_start 与vmalloc_end 之间的「动态内存映射区」。
一般用分配大块内存,释放内存对应于 vfree,分配的虚拟内存地址连续,物理地址上不一定连续。函数原型在 <linux/vmalloc.h> 中声明。一般用在为活动的交换区分配数据结构,为某些 I/O 驱动程序分配缓冲区,或为内核模块分配空间。

下面说一下 dma_map_sg 接口

	int i, count = dma_map_sg(dev, sglist, nents, direction);
	struct scatterlist *sg;

	for_each_sg(sglist, sg, count, i) {
		hw_address[i] = sg_dma_address(sg);
		hw_len[i] = sg_dma_len(sg);
	}

count 个 sg 里面的地址也都是连续的物理地址。即使有 dma_map_sg 接口的条件是可以使用多个不连续的物理地址,但是每段地址必须是连续的。

  • 4
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值