`
mmdev
  • 浏览: 12889904 次
  • 性别: Icon_minigender_1
  • 来自: 大连
文章分类
社区版块
存档分类
最新评论

LDD3学习笔记(18):内存映射和DMA

 
阅读更多

1、介绍性材料

#include<linux/mm.h>

#include<asm/page.h>

和内存管理相关的大部分函数和结构,原型和定义在这些头文件.

void*__va(unsignedlongphysaddr);

unsignedlong__pa(void*kaddr);

在内核逻辑地址和物理地址之间转换的宏定义.

PAGE_SIZE

PAGE_SHIFT

常量,给出底层硬件的页的大小(字节)和一个页面号必须被移位来转变为一个物理地址的位

.

structpage

在系统内存映射中表示一个硬件页的结构.

structpage*virt_to_page(void*kaddr);

void*page_address(structpage*page);

structpage*pfn_to_page(intpfn);

宏定义,在内核逻辑地址和它们相关的内存映射入口之间转换的.page_address只用在低地址

页或者已被明确映射的高地址页.pfn_to_page转换一个页面号到它的相关的structpage指针.

unsignedlongkmap(structpage*page);

voidkunmap(structpage*page);

kmap返回一个内核虚拟地址,被映射到给定页,如果需要并创建映射.kunmap为给定页删除

映射.

#include<linux/highmem.h>

#include<asm/kmap_types.h>

void*kmap_atomic(structpage*page,enumkm_typetype);

voidkunmap_atomic(void*addr,enumkm_typetype);

kmap的高性能版本;结果的映射只能被原子代码持有.对于驱动,type应当是KM_USER1,

KM_USER1,KM_IRQ0,或者KM_IRQ1.

structvm_area_struct;

描述一个VMA的结构.

2、实现mmap

intremap_pfn_range(structvm_area_struct*vma,unsignedlongvirt_add,unsignedlongpfn,unsignedlong

size,pgprot_tprot);

intio_remap_page_range(structvm_area_struct*vma,unsignedlongvirt_add,unsignedlongphys_add,

unsignedlongsize,pgprot_tprot);

位于mmap核心的函数.它们映射size字节的物理地址,pfn指出的页号开始到虚拟地址

virt_add.和虚拟空间相关联的保护位在prot里指定.io_remap_page_range应当在目标地址在

I/O内存空间里时被使用.

structpage*vmalloc_to_page(void*vmaddr);

转换一个由vmalloc获得的内核虚拟地址到它的对应的structpage指针.

3、实现直接I/O

intget_user_pages(structtask_struct*tsk,structmm_struct*mm,unsignedlongstart,intlen,intwrite,int

force,structpage**pages,structvm_area_struct**vmas);

函数,加锁一个用户空间缓冲到内存并且返回对应的structpage指针.调用者必须持有mm-

>mmap_sem.

SetPageDirty(structpage*page);

宏定义,标识给定的页为""(被修改)并且需要写到它的后备存储,在它被释放前.

voidpage_cache_release(structpage*page);

释放给定的页从页缓存中.

intis_sync_kiocb(structkiocb*iocb);

宏定义,返回非零如果给定的IOCB需要同步执行.

intaio_complete(structkiocb*iocb,longres,longres2);

函数,指示一个异步I/O操作完成.

4、直接内存存取

#include<asm/io.h>

unsignedlongvirt_to_bus(volatilevoid*address);

void*bus_to_virt(unsignedlongaddress);

过时的不好的函数,在内核,虚拟,和总线地址之间转换.总线地址必须用来和外设通讯.

#include<linux/dma-mapping.h>

需要来定义通用DMA函数的头文件.

intdma_set_mask(structdevice*dev,u64mask);

对于无法寻址整个32-位范围的外设,这个函数通知内核可寻址的地址范围并且如果可进行

DMA返回非零.

void*dma_alloc_coherent(structdevice*dev,size_tsize,dma_addr_t*bus_addr,intflag);

voiddma_free_coherent(structdevice*dev,size_tsize,void*cpuaddr,dma_handle_tbus_addr);

分配和释放一致DMA映射,对一个将持续在驱动的生命周期中的缓冲.

#include<linux/dmapool.h>

structdma_pool*dma_pool_create(constchar*name,structdevice*dev,size_tsize,size_talign,size_t

allocation);

voiddma_pool_destroy(structdma_pool*pool);

void*dma_pool_alloc(structdma_pool*pool,intmem_flags,dma_addr_t*handle);

voiddma_pool_free(structdma_pool*pool,void*vaddr,dma_addr_thandle);

创建,销毁,和使用DMA池来管理小DMA区的函数.

enumdma_data_direction;

DMA_TO_DEVICE

DMA_FROM_DEVICE

DMA_BIDIRECTIONAL

DMA_NONE

符号,用来告知流映射函数在什么方向数据移入或出缓冲.

dma_addr_tdma_map_single(structdevice*dev,void*buffer,size_tsize,enumdma_data_direction

direction);

voiddma_unmap_single(structdevice*dev,dma_addr_tbus_addr,size_tsize,enumdma_data_direction

direction);

创建和销毁一个单使用,DMA映射.

voiddma_sync_single_for_cpu(structdevice*dev,dma_handle_tbus_addr,size_tsize,enum

dma_data_directiondirection);

voiddma_sync_single_for_device(structdevice*dev,dma_handle_tbus_addr,size_tsize,enumdma_data_directiondirection);

同步一个由一个流映射的缓冲.必须使用这些函数,如果处理器必须存取一个缓冲当使用流

映射时.(,当设备拥有缓冲时).

#include<asm/scatterlist.h>

structscatterlist{/*...*/};

dma_addr_tsg_dma_address(structscatterlist*sg);

unsignedintsg_dma_len(structscatterlist*sg);

这个散布表结构描述一个涉及不止一个缓冲的I/O操作.sg_dma_addresshesg_dma_len

用来抽取总线地址和缓冲长度来传递给设备,当实现发散/汇聚操作时.

dma_map_sg(structdevice*dev,structscatterlist*list,intnents,enumdma_data_directiondirection);

dma_unmap_sg(structdevice*dev,structscatterlist*list,intnents,enumdma_data_directiondirection);

voiddma_sync_sg_for_cpu(structdevice*dev,structscatterlist*sg,intnents,enumdma_data_direction

direction);

voiddma_sync_sg_for_device(structdevice*dev,structscatterlist*sg,intnents,enumdma_data_direction

direction);

dma_map_sg映射一个发散/汇聚操作,并且dma_unmap_sg恢复这些映射.如果在这个映射

被激活时缓冲必须被存取,dma_sync_sg_*可用来同步.

/proc/dma

包含在DMA控制器中的被分配的通道的文本快照的文件.基于PCIDMA不显示,因为每

个板独立工作,不需要分配一个通道在DMA控制器中.

#include<asm/dma.h>

定义或者原型化所有和DMA相关的函数和宏定义.它必须被包含来使用任何下面符号.

intrequest_dma(unsignedintchannel,constchar*name);

voidfree_dma(unsignedintchannel);

存取DMA注册.注册必须在使用ISADMA通道之前进行.

unsignedlongclaim_dma_lock();

voidrelease_dma_lock(unsignedlongflags);

获取和释放DMA自旋锁,它必须被持有,在调用其他的在这个列表中描述的ISADMA函数

之前.它们在本地处理器上也关闭和重新使能中断

voidset_dma_mode(unsignedintchannel,charmode);

voidset_dma_addr(unsignedintchannel,unsignedintaddr);

voidset_dma_count(unsignedintchannel,unsignedintcount);

编程DMA信息在DMA控制器中.addr是一个总线地址.

voiddisable_dma(unsignedintchannel);

voidenable_dma(unsignedintchannel);

一个DMA通道必须被关闭在配置期间.这些函数改变DMA通道的状态.

intget_dma_residue(unsignedintchannel);

如果这驱动需要知道一个DMA传送在进行,它可调用这个函数,返回尚未完成的数据传输

的数目.在成功的DMA完成后,这个函数返回0;值是不可预测的当数据仍然在传送时.

voidclear_dma_ff(unsignedintchannel);

DMAflip-flop被控制器用来传送16-位值,通过28位操作.它必须被清除,在发送任何数

据给处理器之前.

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics