dma mapping

18 篇文章 1 订阅
12 篇文章 0 订阅

 

mips架构:

void *dma_alloc_coherent(struct device *dev, size_t size,
 dma_addr_t * dma_handle, gfp_t gfp)
{
 void *ret;

 if (dma_alloc_from_coherent(dev, size, dma_handle, &ret))
  return ret;

 gfp = massage_gfp_flags(dev, gfp);

 ret = (void *) __get_free_pages(gfp, get_order(size));

 if (ret) {
  memset(ret, 0, size);
  *dma_handle = plat_map_dma_mem(dev, ret, size);

  if (!plat_device_is_coherent(dev)) {
   dma_cache_wback_inv((unsigned long) ret, size);
   ret = UNCAC_ADDR(ret);
  }
 }

 return ret;
}

EXPORT_SYMBOL(dma_alloc_coherent);

参数dma_handle保存了获取到地址的物理地址,对mips架构而言,该函数的返回值(也就是返回的内核虚拟地址)位于unmapped & uncached的kseg1。

 

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

/*
 * Allocate DMA-coherent memory space and return both the kernel remapped
 * virtual and bus address for that space.
 */
void *
dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp)
{
 void *memory;

 if (dma_alloc_from_coherent(dev, size, handle, &memory))
  return memory;

 return __dma_alloc(dev, size, handle, gfp,
      pgprot_dmacoherent(pgprot_kernel),
      __builtin_return_address(0));
}
EXPORT_SYMBOL(dma_alloc_coherent);

其中:

#ifdef CONFIG_ARM_DMA_MEM_BUFFERABLE
#define pgprot_dmacoherent(prot) \
 __pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_BUFFERABLE | L_PTE_XN)
#define __HAVE_PHYS_MEM_ACCESS_PROT
struct file;
extern pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
         unsigned long size, pgprot_t vma_prot);
#else
#define pgprot_dmacoherent(prot) \
 __pgprot_modify(prot, L_PTE_MT_MASK, L_PTE_MT_UNCACHED | L_PTE_XN)
#endif

 

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

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

 

 

另外说明一下:

在linux-3.4\arch\mips\include\asm\Dma-mapping.h 中有:

#include <asm-generic/dma-mapping-common.h>
所以mips架构dma_map_single就位于dma-mapping-common.h中:

#define dma_map_single(d, a, s, r) dma_map_single_attrs(d, a, s, r, NULL)

对arm架构而言,dma_map_single的实现在linux-3.4\arch\arm\include\asm\dma-mapping.h中:

static inline dma_addr_t dma_map_single(struct device *dev, void *cpu_addr,
  size_t size, enum dma_data_direction dir)
{
 unsigned long offset;
 struct page *page;
 dma_addr_t addr;

 BUG_ON(!virt_addr_valid(cpu_addr));
 BUG_ON(!virt_addr_valid(cpu_addr + size - 1));
 BUG_ON(!valid_dma_direction(dir));

 page = virt_to_page(cpu_addr);
 offset = (unsigned long)cpu_addr & ~PAGE_MASK;
 addr = __dma_map_page(dev, page, offset, size, dir);
 debug_dma_map_page(dev, page, offset, size, dir, addr, true);

 return addr;
}

 

linux-3.4\documentation\DMA-API-HOWTO.txt解释是:

   If your architecture needs to support multiple types of IOMMUs, you can use include/linux/asm-generic/dma-mapping-common.h. It's a library to support the DMA API with multiple types of IOMMUs. Lots of architectures (x86, powerpc, sh, alpha, ia64, microblaze and sparc) use it. Choose one to see how it can be used. If you need to support multiple types of IOMMUs in a single system, the example of x86 or powerpc helps.

如果架构支持多种IOMMU,可以使用dma-mapping-common.h。

 

http://blog.chinaunix.net/uid-27123777-id-3279668.html

mips一致性DMA映射、流式DMA映射的使用

http://www.cnblogs.com/hoys/archive/2012/06/21/2557889.html

内核使用硬件ip的dma,dma_alloc_coherent 与 dma_alloc_writecombine (转)

http://blog.chinaunix.net/uid-9185047-id-445099.html

dma_alloc_coherent 与 dma_alloc_writecombine区别 (2010-08-02 16:02)

http://www.360doc.com/content/11/1014/12/1317564_156096743.shtml

DMA及cache一致性学习心得

linux之dma api -- 通用设备的动态dma映射

http://www.58os.com/BBS/OSChinaBlog/Article-858.html

 

下面这篇文章是内核文档DMA-API-HOWTO.txt的翻译,可结合来看。

 DMA动态映射指南

http://www.tuicool.com/articles/biAvi2

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值