Linux DMA meory 及一致性简述文档格式.docx
- 文档编号:19282124
- 上传时间:2023-01-05
- 格式:DOCX
- 页数:8
- 大小:17.86KB
Linux DMA meory 及一致性简述文档格式.docx
《Linux DMA meory 及一致性简述文档格式.docx》由会员分享,可在线阅读,更多相关《Linux DMA meory 及一致性简述文档格式.docx(8页珍藏版)》请在冰豆网上搜索。
首先,应该先读Documentation/DMA-API.txt和DMA-mapping.txt.
DMAmemeory分类
一共有两种DMAmemory,
a.
Consistent/coherent
b.
non-consistent/no-coherent
第一类由底层硬件保证了内存的一致性,这样的内存当进行DMA时,不需要相关的invalidate函数操作。
第二类内存在进行DMA之前,必须做flush/invalidate等操作。
底层硬件如何实现,或者处理器通过内存映射,或者有额外的硬件支持,这些对于driver来说是透明的。
注意
coherent和no-coherent和cache是不同的概念,coherent也许是cached,也许是uncached,这是由底层硬件来实现。
DMA对memory的操作函数
DMA-API有两类,
第一类是dma_API,
它必须包含#include<
linux/dma-mapping.h>
第二类是pci_API,
linux/pci.h>
第一类是向处理器直接分配内存,第二类是通过pci的接口分配内存。
对于mips和arm来说,这两类API是一样的,pci_API在mips和arm处理器中最后会走到dma_API
所以这里只提及DMA-API
dma_alloc_coherent
分配coherent内存。
一般来说,coherent内存是比较昂贵,或者代价比较高一些,所以只能小块的内存使用coherent,比如典型的descriptor。
dma_pool_create
这个用来分配一个小块coherent的内存池子。
dma_alloc_coherent是以页为单位分配。
dma_sync_single_for_device
dma_sync_single_for_cpu
并不太确定这两个sync是啥意思,很重要的两个函数,在mips上的实现也不同,一个是做了flush的动作,一个是没做
dma_map_single
flush这段内存,并返回物理地址,当分配buffer的时候,通常会使用这个函数返回物理地址。
DMA的层次结构
3.1
对于DMA_API来说,从<
开始,这里定义了一些公共的API,然后在这个头文件中会
#ifdefCONFIG_HAS_DMA
#include<
asm/dma-mapping.h>
#else
asm-generic/dma-mapping-broken.h>
#endif
一般我们会定义CONFIG_HAS_DMA,所以会包含体系相关的dma-mapping.h。
对于mips来说,是arch/mips/include/asm/dma-mapping.h
对于arm来说,是arch/arm/include/asm/dma-mapping.h
在这两个头文件中,可以直接调用到各个arch中的dmamapping的实现,也可以在封装一层,
再包含#includedma-maping-common.h,然后这里通过dma_map_ops函数指针调到各个arch的dmamapping实现。
体系相关的dma-mapping.h中声明了其它DMA_API。
它在哪里实现了,
对于mips来说,它在arch/mips/mm/dma-default.c
对于arm来说,它在arch/arm/mm/dma-mapping.c
对于PCI_API来说,从<
开始。
这个头文件会包含体系相关的<
asm/pci.h>
对于mips来说,是arch/mips/include/asm/pci.h
对于arm来说,是arch/arm/include/asm/pci.h
对于mips和arm来说,pci.h又会包含如下语句
/*implementthepci_DMAAPIintermsofthegenericdevicedma_one*/
asm-generic/pci-dma-compat.h>
然后在pci-dma-compat.h里,开始包含#include<
,并且把PCI_向DMA_做了转换,这就把PCI_和DMA_联系上了。
MIPS上的DMA实现
在dma-default.c中实现了mips的DMA函数
void*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((unsignedlong)ret,size);
ret=UNCAC_ADDR(ret);
}
returnret;
从这个函数可以看出,mips分配一个页面,清空,返回物理地址,然后判断这个device是否是coherent,因为我们前面说过可以有额外的硬件来支持coherent。
plat_device_is_coherent
{
#ifdefCONFIG_DMA_COHERENT
return1;
#ifdefCONFIG_DMA_NONCOHERENT
return0;
对于mips来讲,它依据CONFIG_DMA_COHERENT和CONFIG_DMA_NONCOHERENT
定义。
它只是提供了这样一个函数给所有的平台。
一般我们会定义CONFIG_DMA_NONCOHERENT。
所以这里,mips是如何操作这coherent函数的呢?
它把这一页先write-inv,
然后返回SEG1地址,其实就是uncache,这样确实保证了coherent,但效率会变低。
dma_addr_tdma_map_single(structdevice*dev,void*ptr,size_tsize,
enumdma_data_directiondirection)
unsignedlongaddr=(unsignedlong)ptr;
plat_device_is_coherent(dev))
__dma_sync(addr,size,direction);
returnplat_map_dma_mem(dev,ptr,size);
Dma_map_single有sync的作用,并且返回物理地址。
staticinlinevoid__dma_sync(unsignedlongaddr,size_tsize,
switch(direction){
caseDMA_TO_DEVICE:
dma_cache_wback(addr,size);
break;
caseDMA_FROM_DEVICE:
dma_cache_inv(addr,size);
caseDMA_BIDIRECTIONAL:
dma_cache_wback_inv(addr,size);
default:
BUG();
对于写device,我们需要wback,对于从device读,我们需要invalidate,对于双向,我们需要invalidate+wback。
这个涉及到cache的操作了,具体如何操作,与cache的类型相关。
在arch/mips/include/asm/io.h中
#definedma_cache_wback_inv(start,size)
_dma_cache_wback_inv(start,size)
#definedma_cache_wback(start,size)
_dma_cache_wback(start,size)
#definedma_cache_inv(start,size)
_dma_cache_inv(start,size)
而_dma_cache_wback_inv这些底层函数的赋值则是在系统起来,初始化cache时赋值的,mips有多种类型,对于24K,74K等,它会使用原先的R4kcache,这里我们要选择CONFIG_CSRC_R4K=y。
在r4k_cache_init函数中
_dma_cache_wback_inv
=r4k_dma_cache_wback_inv;
_dma_cache_wback
_dma_cache_inv
=r4k_dma_cache_inv;
所以最后DMA的操作到了r4k的cache操作上来。
ARM上的DMA实现
因为不太懂ARM,这里只说一下armcache的层次结构。
一般如果要sync一个buffer,arm提供到外面的接口有
___dma_single_cpu_to_dev
___dma_single_dev_to_cpu
我不知道这两个的区别,这个要留到以后分析。
BUG_ON(!
virt_addr_valid(kaddr)||!
virt_addr_valid(kaddr+size-1));
/*FIXME:
non-speculating:
notrequired*/
/*don'
tbotherinvalidatingifDMAtodevice*/
if(dir!
=DMA_TO_DEVICE){
unsignedlongpaddr=__pa(kaddr);
outer_inv_range(paddr,paddr+size);
dmac_unmap_area(kaddr,size,dir);
definedmac_unmap_area
cpu_cache.dma_unmap_area
如果有需要还要使用outer_inv_range来invalidateL2的cache。
然后需要dmac_unmap_area
这个函数在cacheflush.h中有定义,表示为cpu_cache.dma_unmap_area,这个文件中还定义
了很多其它cache的操作,因为arm有不同的型号,所以每一种
cache都不一样。
在arch/arm/mm下面,cpu_cache在如下函数中定义
如果CPU是ARMV7的话,则在cache-v7.S最后两句,定义了这个结构
@definestructcpu_cache_fns(see<
asm/cacheflush.h>
andproc-macros.S)
define_cache_functionsv7
而define_cache_functions
v7则是在proc-macros.S中定义
ENTRY(\name\()_cache_fns)
.long
\name\()_flush_icache_all
其实就是
v7_flush_icache_all等。
而v7_flush_icache_all这些函数的定义
则是在cache-v7.S中
如
ENTRY(v7_dma_unmap_area)
add
r1,r1,r0
teq
r2,#DMA_TO_DEVICE
bne
v7_dma_inv_range
mov
pc,lr
ENDPROC(v7_dma_unmap_area)
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Linux DMA meory 及一致性简述 一致性 简述