Linux DMA使用(网摘)关键词:0引言1如何在Linux下用DMA的方式进行数据传输(硬盘)我们都知道,使用DMA方式传输数据可以占用更少的CPU资源,因此与其它操作系统一样,Linux支持硬盘以DMA方式转输数据,但在安装Red Hat时关于DMA的默认选项是Disable的,当然你可以在安装时就enable它。
如果在安装时DMA是disable的,那该怎么才能激活DMA呢?通过重新编译内核可以激活DMA支持,但编译内核对新手显然太过复杂。
下面的方法无需编译内核,就可以激活DMA支持。
一、检查系统中的DMA选项是否已被激活在进行操作前,先确认硬盘是否已经在使用DMA方式传输数据了。
方法:查看/ proc/ide/hda/settings文件,其中有一行的内容为:using_dma,如果其后面的值被设置为1就说明系统已经支持DMA了,那么下面的操作就可以免了,当然如果你要关闭DMA 功能的话,还要往下看看哟:)。
Linux中的hdparm命令是用来进行与硬盘相关操作的,用hdparm-i/dev/hda可以列出IDE可能支持的DMA模式,如:DMA modes:mdma0mdma1mdma2udma0udma1udma2udma3*udma4二、激活DMA支持方法1:在lilo.conf中加入:idex=dma,其中x代表硬盘序号,其取值范围0-3,分别代表系统中的四个IDE硬盘设备。
方法2:使用hdparm命令,hdparm d1/dev/hda其中d1表示使能DMA,你可以将其加到rc.locl中以便每次启动时都硬盘都能使用DMA方式传输数据。
三、关闭DMA支持命令格式:hdparm d0/dev/hda关闭DMA传输方式,实在想不出有什么理由要这样做。
对支持UDMA传输方式的硬盘,也可以参照以上的方法进行设置,但要确保硬盘控制器及硬盘都支持UDMA,最后你还要有一根支持UDMA传输方式的硬盘连线,否则即使你激活了UDMA支持,它也会罢工的。
2S3C2410的linux下DMA驱动程序开发网上介绍LINUX下的一般驱动程序开发示例浩如烟海,或是因为简单,关于DMA驱动的介绍却寥寥无几;近期zhaoyang因工作需要,花了几日时间开发了某设备在S3C2410处理器Linux下DMA通信的驱动程序,有感于刚接手时无资料借鉴的茫然,故写点介绍,期待能给有DMA开发任务的网友们一点帮助。
本文将包括如下内容:DMA驱动主要函数功能驱动中关键技术分析具体的DMA实例分析申明:本DMA驱动开发介绍仅适合S3C2410处理器类型,分析源码为韩国MIZI研究中心维护的dma驱动代码:linux/arch/arm/mach-s3c2410/dma.h,linux /arch/arm/mach-s3c2410/dma.c,其它处理器平台DMA开发可比对此文,自行分析。
DMA驱动主要数据结构(linux/arch/arm/mach-s3c2410/dma.h)S3C2410有四通道DMA,每通道有9个控制寄存器:6个控制寄存器控制DMA传输,其它3个监视DMA控制器状态。
(1)DMA单个内核缓冲区数据结构:typedef struct dma_buf_s{int size;/*buffer size:缓冲大小*/dma_addr_t dma_start;/*starting DMA address:缓冲区起始物理地址*/int ref;/*number of DMA references缓冲区起始虚拟地址*/void*id;/*to identify buffer from outside标记*/int write;/*1:buf to write,0:buf to read DMA读还是写*/struct dma_buf_s*next;/*next buf to process指向下一个缓冲区结构*/ }dma_buf_t;(2)DMA寄存器数据结构/*DMA control register structure*/typedef struct{volatile u_long DISRC;/源地址寄存器volatile u_long DISRCC;//源控制寄存器volatile u_long DIDST;//目的寄存器volatile u_long DIDSTC;//目的控制寄存器volatile u_long DCON;//DMA控制寄存器volatile u_long DSTAT;//状态寄存器volatile u_long DCSRC;//当前源volatile u_long DCDST;//当前目的volatile u_long DMASKTRIG;//触发掩码寄存器}dma_regs_t;(3)DMA设备数据结构/*DMA device structre*/typedef struct{dma_callback_t callback;//DMA操作完成后的回调函数,在中断处理例程中调用u_long dst;//目的寄存器内容u_long src;//源寄存器内容u_long ctl;//此设备的控制寄存器内容u_long dst_ctl;//目的控制寄存器内容u_long src_ctl;//源控制寄存器内容}dma_device_t;(4)DMA通道数据结构/*DMA channel structure*/typedef struct{dmach_t channel;//通道号:可为0,1,2,3unsigned int in_use;/*Device is allocated设备是否已*/const char*device_id;/*Device name设备名*/dma_buf_t*head;/*where to insert buffers该DMA通道缓冲区链表头*/dma_buf_t*tail;/*where to remove buffers该DMA通道缓冲区链表尾*/dma_buf_t*curr;/*buffer currently DMA'ed该DMA通道缓冲区链表中的当前缓冲区*/unsigned long queue_count;/*number of buffers in the queue链表中缓冲区个数*/int active;/*1if DMA is actually processing data该通道是否已经在使用*/dma_regs_t*regs;/*points to appropriate DMA registers该通道使用的DMA 控制寄存器*/int irq;/*IRQ used by the channel//通道申请的中断号*/dma_device_t write;/*to write//执行读操作的DMA设备*/dma_device_t read;/*to read执行写操作的DMA设备*/}s3c2410_dma_t;以下分配了四个DMA通道:s3c2410_dma_t dma_chan[MAX_S3C2410_DMA_CHANNELS];每个DMA通道维护着一个多缓冲区组成的单链表等待队列,执行DMA操作时先更新DMA 通道控制寄存器内容,再依次摘取当前缓冲区投入使用,缓冲区头指针顺次前移;需要插入新的缓冲区时,可从head或tail插入;图A详细分析了数据结构关系:DMA驱动主要函数功能分析(linux/arch/arm/mach-s3c2410/dma.c)写一个DMA驱动的主要工作包括:DMA通道申请、DMA中断申请、控制寄存器设置、挂入DMA等待队列、清除DMA中断、释放DMA通道。
Dma.c中对这些工作作了很好的实现,以下具体分析关键函数:int s3c2410_request_dma(const char*device_id,dmach_t channel,dma_callback_t write_cb,dma_callback_t read_cb)(s3c2410_dma_queue_buffer);函数描述:申请某通道的DMA资源,填充s3c2410_dma_t数据结构的内容,申请DMA 中断。
输入参数:device_id DMA设备名;channel通道号;write_cb DMA写操作完成的回调函数;read_cb DMA读操作完成的回调函数输出参数:若channel通道已使用,出错返回;否则,返回0int s3c2410_dma_queue_buffer(dmach_t channel,void*buf_id,dma_addr_t data,int size,int write)(s3c2410_dma_stop);函数描述:这是DMA操作最关键的函数,它完成了一系列动作:分配并初始化一个DMA 内核缓冲区控制结构,并将它插入DMA等待队列,设置DMA控制寄存器内容,等待DMA 操作触发输入参数:channel通道号;buf_id,缓冲区标识dma_addr_t data DMA数据缓冲区起始物理地址;size DMA数据缓冲区大小;write是写还是读操作输出参数:操作成功,返回0;否则,返回错误号int s3c2410_dma_stop(dmach_t channel)函数描述:停止DMA操作。
int s3c2410_dma_flush_all(dmach_t channel)函数描述:释放DMA通道所申请的所有内存资源void s3c2410_free_dma(dmach_t channel)函数描述:释放DMA通道因为各函数功能强大,一个完整的DMA驱动程序中一般只需调用以上3个函数即可。
可在驱动初始化中调用s3c2410_request_dma,开始DMA传输前调用s3c2410_ dma_queue_buffer,释放驱动模块时调用s3c2410_free_dma。
具体的DMA实例分析Linux下的IIS音频驱动主要都在/kernel/drivers/sound/s3c2410-uda1341.c文件中。
它定义了2个重要的数据结构audio_bufer_t,管理audio缓冲区的数据结构;audio_stream_t管理多缓冲区的数据结构,它为音频流数据组成了一个环形缓冲区。
我们先看一下加载驱动模块时的初始化函数:int__init s3c2410_uda1341_init(void),该函数先初始化IO和UDA341芯片,然后语句s3c2410_request_dma("I2SSDO",s ->dma_ch,audio_dmaout_done_callback,NULL);申请了一个DMA通道用于输出音频数据;smdk2410_audio_write是音频驱动最关键的函数,它从用户进程中拷贝音频数据流至DMA内核缓冲区,然后适用DMA通道2把音频数据发送出去,从而输出声音。