申请noncache内存

申请内存提供给用户态,nocache

static int shm_mmap(struct dma_buf *dmabuf, struct vm_area_struct *vma)
{
    struct tee_shm *shm = dmabuf->priv;
    size_t size = vma->vm_end - vma->vm_start;
    
    vma->vm_flags |= VM_IO | VM_SHARED; (VM_SHARED 或者 VM_RESEVERED根据自己需求选择)
    vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
    return remap_pfn_range(vma, vma->vm_start, shm->paddr >> PAGE_SHIFT,
                  size, vma->vm_page_prot);
}

内核态申请的内存,nocache,方法如下,使用者两个函数dma_alloc_coherent 与 dma_alloc_writecombine。如果觉得麻烦,可以参考着两个接口,自己实现一遍。dma_alloc_coherent的代码实现分析,请看另外一篇文章

内核的dma一般在平台初始化的时候已经分配好了。但是对于一些有内部dma的硬件ip,比如usb ip、video加速ip,他们可能由ip厂商封装好的,没办法绑定到cpu端,这时候在内核使用dma就要注意了,因为dma只认识物理地址哦。

当然,办法还是有的,look:

以下来自:http://blog.csdn.net/zjujoe/archive/2009/05/15/4189612.aspx

这两天在做 DMA 相关开发, 遇到一对分配 dma buffer 的函数,dma_alloc_coherent 与 dma_alloc_writecombine。 不知其区别。 google 一下也没有得到信息。只好自己看代码。

原来 dma_alloc_coherent 在 arm 平台上会禁止页表项中的 C (Cacheable) 域以及 B (Bufferable)域。

而 dma_alloc_writecombine 只禁止 C (Cacheable) 域.

#define pgprot_noncached(prot)  __pgprot(pgprot_val(prot) & ~(L_PTE_CACHEABLE | L_PTE_BUFFERABLE))
#define pgprot_writecombine(prot) __pgprot(pgprot_val(prot) & ~L_PTE_CACHEABLE)

进一步查找 ARM 书籍, 原来 C 代表是否使用高速缓冲存储器, 而 W 代表是否使用写缓冲区。

这样, dma_alloc_coherent  分配出来的内存不使用缓存,但是会使用写缓冲区。

而 dma_alloc_writecombine 则二者都不适用。

 

 

由此,再去理解 LDD3 上讲解的一致性 DMA 映射 与 流式 DMA 映射就比较容易了,一致性 DMA 映射调用的是上面的函数,   由于关闭了 cache/buffer, 性能自然比较低。 而流式则通过复杂的同步机制,没有付出性能的代价。

所以我们要尽量使用流式 DMA 来编程。

 

再去看看 mmc 驱动里使用的 分散 / 聚集映射, 原来也是一种 流式 DMA 映射。

 

【补充】

讲了那么多没用,总结下用法:

1、页对齐内存大小:dma_map_size = PAGE_ALIGN(MY_DATA_SIZE + PAGE_SIZE);

MY_DATA_SIZE是你想分配的大小.

2、调用

A = dma_alloc_writecombine(B,C,D,GFP_KERNEL);

含义:

A: 内存的虚拟起始地址,在内核要用此地址来操作所分配的内存

B: struct device指针,可以平台初始化里指定,主要是dma_mask之类,可参考framebuffer

C: 实际分配大小,传入dma_map_size即可

D: 返回的内存物理地址,dma就可以用。

所以,A和D是一一对应的,只不过,A是虚拟地址,而D是物理地址。对任意一个操作都将改变缓冲区内容。当然要注意操作环境。 

 

大家都知道,DMA的操作是需要物理地址的,但是在linux内核中使用的都是虚拟地址,如果我们想要用DMA对一段内存进行操作,我们如何得到这一段内存的物理地址和虚拟地址的映射呢?dma_alloc_coherent这个函数实现了这种机制。
1、函数原型:void *dma_alloc_coherent(struct device *dev, size_t size,dma_addr_t *dma_handle,gfp_t gfp);下面的这一段参考http://blog.csdn.net/lanmanck/archive/2009/11/05/4773175.aspx

2、调用

A = dma_alloc_writecombine(B,C,D,GFP_KERNEL);

含义:

A: 内存的虚拟起始地址,在内核要用此地址来操作所分配的内存

B: struct device指针,可以平台初始化里指定,主要是dma_mask之类,可参考framebuffer

C: 实际分配大小,传入dma_map_size即可

D: 返回的内存物理地址,dma就可以用。

所以,A和D是一一对应的,只不过,A是虚拟地址,而D是物理地址。对任意一个操作都将改变缓冲区内容。

 

我对此函数的理解是,调用此函数将会分配一段内存,D将返回这段内存的实际物理地址供DMA来使用,A将是D对应的

虚拟地址供操作系统调用,对A和D的的任意一个进行操作,都会改变这段内存缓冲区的内容。

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值