Linux DMA驱动构架分析.docx

上传人:b****7 文档编号:11214312 上传时间:2023-02-25 格式:DOCX 页数:17 大小:21.88KB
下载 相关 举报
Linux DMA驱动构架分析.docx_第1页
第1页 / 共17页
Linux DMA驱动构架分析.docx_第2页
第2页 / 共17页
Linux DMA驱动构架分析.docx_第3页
第3页 / 共17页
Linux DMA驱动构架分析.docx_第4页
第4页 / 共17页
Linux DMA驱动构架分析.docx_第5页
第5页 / 共17页
点击查看更多>>
下载资源
资源描述

Linux DMA驱动构架分析.docx

《Linux DMA驱动构架分析.docx》由会员分享,可在线阅读,更多相关《Linux DMA驱动构架分析.docx(17页珍藏版)》请在冰豆网上搜索。

Linux DMA驱动构架分析.docx

LinuxDMA驱动构架分析

LinuxDMA驱动构架分析

以linux2.6.32中的S3C2440驱动为例进行分析,DMA驱动所对应的源码为linux-2.6.32.2\arch\arm\mach-s3c2440\dma.c,代码入口为:

arch_initcall(s3c2440_dma_init);

205staticint__inits3c2440_dma_init(void)

206{

207returnsysdev_driver_register(&s3c2440_sysclass,&s3c2440_dma_driver);

208}

DMA驱动作为系统驱动由sysdev_driver_register来向内核注册,这里只关注s3c2440_dma_driver相关的内容,即调用drive中的add方法,其他的kobject对象略过。

201staticstructsysdev_drivers3c2440_dma_driver={

202.add=s3c2440_dma_add,

203};

s3c2440_dma_add做了一系列的初始化工作,相应的代码如下:

194staticint__inits3c2440_dma_add(structsys_device*sysdev)

195{

196s3c2410_dma_init();

197s3c24xx_dma_order_set(&s3c2440_dma_order);

198returns3c24xx_dma_init_map(&s3c2440_dma_sel);

199}

下面就其中出的三个函数一一进行分析。

一、

s3c2410_dma_init

首先s3c2410_dma_init()调用了plat-s3c24xx平台公共的函数s3c24xx_dma_init(4,IRQ_DMA0,0x40);

1306int__inits3c24xx_dma_init(unsignedintchannels,unsignedintirq,

1307unsignedintstride)

1308{

1309structs3c2410_dma_chan*cp;

1310intchannel;

1311intret;

1312

1313printk("S3C24XXDMADriver,(c)2003-2004,2006SimtecElectronics\n");

1314

1315dma_channels=channels;

1316

1317dma_base=ioremap(S3C24XX_PA_DMA,stride*channels);

1318if(dma_base==NULL){

1319printk(KERN_ERR"dmafailedtoremapregisterblock\n");

1320return-ENOMEM;

1321}

1322

1323dma_kmem=kmem_cache_create("dma_desc",

1324sizeof(structs3c2410_dma_buf),0,

1325SLAB_HWCACHE_ALIGN,

1326s3c2410_dma_cache_ctor);

1327

1328if(dma_kmem==NULL){

1329printk(KERN_ERR"dmafailedtomakekmemcache\n");

1330ret=-ENOMEM;

1331gotoerr;

1332}

1333

1334for(channel=0;channel

1335cp=&s3c2410_chans[channel];

1336

1337memset(cp,0,sizeof(structs3c2410_dma_chan));

1338

1339/*dmachannelirqsareinorder..*/

1340cp->number=channel;

1341cp->irq=channel+irq;

1342cp->regs=dma_base+(channel*stride);

1343

1344/*pointcurrentstatssomewhere*/

1345cp->stats=&cp->stats_store;

1346cp->stats_store.timeout_shortest=LONG_MAX;

1347

1348/*basicchannelconfiguration*/

1349

1350cp->load_timeout=1<<18;

1351

1352printk("DMAchannel%dat%p,irq%d\n",

1353cp->number,cp->regs,cp->irq);

1354}

1355

1356return0;

1357

1358err:

1359kmem_cache_destroy(dma_kmem);

1360iounmap(dma_base);

1361dma_base=NULL;

1362returnret;

1363}

1364

首先来关注一下函数传递的参数:

unsignedintchannels:

s3c2440平台对应的DMA通道总数,为4

unsignedintirq:

起始DMA中断的中断号

unsignedintstride:

每通道DMA所占寄存器资源数

1309行structs3c2410_dma_chan记录dma通道信息,内容如下:

151structs3c2410_dma_chan{

152/*channelstateflagsandinformation*/

153unsignedcharnumber;//dma通道号,

154unsignedcharin_use;//当前通道是否已经使用

155unsignedcharirq_claimed;//有无dma中断

156unsignedcharirq_enabled;//是否使能了dma中断

157unsignedcharxfer_unit;//传输块大小

158

159/*channelstate*/

160

161enums3c2410_dma_statestate;

162enums3c2410_dma_loadstload_state;

163structs3c2410_dma_client*client;

164

165/*channelconfiguration*/

166enums3c2410_dmasrcsource;

167enumdma_chreq_ch;

168unsignedlongdev_addr;

169unsignedlongload_timeout;

170unsignedintflags;/*channelflags*/

171

172structs3c24xx_dma_map*map;/*channelhwmaps*/

173

174/*channel'shardwarepositionandconfiguration*/

175void__iomem*regs;/*channelsregisters*/

176void__iomem*addr_reg;/*dataaddressregister*/

177unsignedintirq;中断号

178unsignedlongdcon;/默认控制寄存器的值

179

180/*driverhandles*/

181s3c2410_dma_cbfn_tcallback_fn;传输完成回调函数

182s3c2410_dma_opfn_top_fn;操作完成回调函数*/

183

184/*statsgathering*/

185structs3c2410_dma_stats*stats;

186structs3c2410_dma_statsstats_store;

187

188/*bufferlistandinformation*/

189structs3c2410_dma_buf*curr;/*currentdmabuffer*/

190structs3c2410_dma_buf*next;/*nextbuffertoload*/

191structs3c2410_dma_buf*end;/*endofqueue*/dma缓冲区链表

192

193/*systemdevice*/

194structsys_devicedev;

195};

1315行dma_channels是全局变量记录了当前系统dma通道总数

1317-1321行映射dma控制寄存器

1323-1332行为structs3c2410_dma_buf分配cache,并利用函数s3c2410_dma_cache_ctor初始化为0。

1334-1354行的循环就是初始化全局数组structs3c2410_dma_chans3c2410_chans[S3C_DMA_CHANNELS];,其中包括通道编号、中断号以及寄存器基地址等信息。

这个数组是针对实际的硬件信息建立的,每个硬件的dma通道唯一对应一个structs3c2410_dma_chan的数据结构。

与之对应的还有一个虚拟的dma通道,其实质是将不同dma请求源区分开来,然后用一个虚拟的通道号与之一一对应,然后与实际的dma通道通过一张map表关联起来。

关于map的相关内容后面将会分析。

二、

s3c24xx_dma_order_set

首先这个函数的意义是预定一些目标板要用的dma通道,使用的是上文提到的虚拟的dma通道号。

1475int__inits3c24xx_dma_order_set(structs3c24xx_dma_order*ord)

1476{

1477structs3c24xx_dma_order*nord=dma_order;

1478

1479if(nord==NULL)

1480nord=kmalloc(sizeof(structs3c24xx_dma_order),GFP_KERNEL);

1481

1482if(nord==NULL){

1483printk(KERN_ERR"nomemorytostoredmachannelorder\n");

1484return-ENOMEM;

1485}

1486

1487dma_order=nord;

1488memcpy(nord,ord,sizeof(structs3c24xx_dma_order));

1489return0;

1490}

1477行dma_order是个全局变量,其作用是记录下目标板的dma预定信息。

这里使用的是s3c2440_dma_order为其赋值,数据如下:

51staticstructs3c24xx_dma_order__initdatas3c2440_dma_order={

52.channels={

53[DMACH_SDI]={

54.list={

55[0]=3|DMA_CH_VALID,

56[1]=2|DMA_CH_VALID,

57[2]=1|DMA_CH_VALID,

58[3]=0|DMA_CH_VALID,

59},

60},

61[DMACH_I2S_IN]={

62.list={

63[0]=1|DMA_CH_VALID,

64[1]=2|DMA_CH_VALID,

65},

66},

67[DMACH_I2S_OUT]={

68.list={

69[0]=2|DMA_CH_VALID,

70[1]=1|DMA_CH_VALID,

71},

72},

73[DMACH_PCM_IN]={

74.list={

75[0]=2|DMA_CH_VALID,

76[1]=1|DMA_CH_VALID,

77},

78},

79[DMACH_PCM_OUT]={

80.list={

81[0]=1|DMA_CH_VALID,

82[1]=3|DMA_CH_VALID,

83},

84},

85[DMACH_MIC_IN]={

86.list={

87[0]=3|DMA_CH_VALID,

88[1]=2|DMA_CH_VALID,

89},

90},

91},

92};

[DMACH_SDI]、[DMACH_I2S_IN]等是系统为dma所分配的虚拟dma通道号,犹如中断子系统为中断分配的中断号一样,与具体硬件的中断向量号是不一致的。

后面我们在系统中使用的dma通道号,都将是内核虚拟出来的,s3c2410_dma_request函数将为用户找到硬件对应的dma通道号。

提取上面[DMACH_SDI]虚拟通道来分析一下:

[DMACH_SDI]={

54.list={

55[0]=3|DMA_CH_VALID,

56[1]=2|DMA_CH_VALID,

57[2]=1|DMA_CH_VALID,

58[3]=0|DMA_CH_VALID,

59},

60},

List这个结构列出的是实际dma通道的可用信息,这里表面对于sdi所能够使用的dma通道包含通道3,2,1,0一共四个通道,为什么从大到小排列是因为某些dma请求只能使用dma0,dma1等较小的通道号,比如外部总线dma只能使用dma0,为了避免sdi占用,这里就采用了这种排列。

三、

s3c24xx_dma_init_map

上面提到过一个map,这里就是为这个map的初始化函数了。

他实际是根据硬件情况为一个全局变量赋值。

与前面的初始化一样,这里主要是为了统一管理plat24xx这个平台下的dma资源,所以不同的芯片必须将自己硬件有关的dma信息初始化到相应的全局变量中。

再说函数之前先来关注一下structs3c24xx_dma_map这个数据结构,他提供了dma虚拟通道与实际的dma通道直接的关联:

structs3c24xx_dma_map{

constchar*name;//虚拟dma通道名称

structs3c24xx_dma_addrhw_addr;

unsignedlongchannels[S3C_DMA_CHANNELS];//实际dma通道信息

unsignedlongchannels_rx[S3C_DMA_CHANNELS];

};

上面的结构只提供了单个虚拟通道的dma视图,整个芯片的虚拟dma通道的分配情况是靠structs3c24xx_dma_map数组完成的。

在这里由structs3c24XX_dma_selection来统一管理。

structs3c24xx_dma_selection{

structs3c24xx_dma_map*map;//记录了structs3c24xx_dma_map数组的首地址

unsignedlongmap_size;//structs3c24xx_dma_map数组的成员个数

unsignedlongdcon_mask;//dma控制器掩码

void(*select)(structs3c2410_dma_chan*chan,

structs3c24xx_dma_map*map);//虚拟通道选择函数

void(*direction)(structs3c2410_dma_chan*chan,

structs3c24xx_dma_map*map,

enums3c2410_dmasrcdir);//dma方向

};

有了上面的背景以后下面函数就是简单的数据拷贝了,函数比较简单不在展开说明。

1454int__inits3c24xx_dma_init_map(structs3c24xx_dma_selection*sel)

1455{

1456structs3c24xx_dma_map*nmap;

1457size_tmap_sz=sizeof(*nmap)*sel->map_size;

1458intptr;

1459

1460nmap=kmalloc(map_sz,GFP_KERNEL);

1461if(nmap==NULL)

1462return-ENOMEM;

1463

1464memcpy(nmap,sel->map,map_sz);

1465memcpy(&dma_sel,sel,sizeof(*sel));

1466

1467dma_sel.map=nmap;

1468

1469for(ptr=0;ptrmap_size;ptr++)

1470s3c24xx_dma_check_entry(nmap+ptr,ptr);

1471

1472return0;

1473}

初始化的任务比较简单,就是

(1)建立硬件dma通道信息即:

structs3c2410_dma_chans3c2410_chans[S3C_DMA_CHANNELS];

(2)建立目标板虚拟dma通道与硬件的dma通道的关联:

staticstructs3c24xx_dma_order*dma_order;

(3)建立芯片本身的虚拟dma通道与硬件dma通道的视图:

staticstructs3c24xx_dma_selectiondma_sel;

完成上述工作以后,基本的dma框架就已经建立起来了。

接下分析dma使用过程中相关的函数:

(一)s3c2410_dma_request

715ints3c2410_dma_request(unsignedintchannel,

716structs3c2410_dma_client*client,

717void*dev)

718{

719structs3c2410_dma_chan*chan;

720unsignedlongflags;

721interr;

722

723pr_debug("dma%d:

s3c2410_request_dma:

client=%s,dev=%p\n",

724channel,client->name,dev);

725

726local_irq_save(flags);

727

728chan=s3c2410_dma_map_channel(channel);

729if(chan==NULL){

730local_irq_restore(flags);

731return-EBUSY;

732}

733

734dbg_showchan(chan);

735

736chan->client=client;

737chan->in_use=1;

738

739if(!

chan->irq_claimed){

740pr_debug("dma%d:

%s:

requestingirq%d\n",

741channel,__func__,chan->irq);

742

743chan->irq_claimed=1;

744local_irq_restore(flags);

745

746err=request_irq(chan->irq,s3c2410_dma_irq,IRQF_DISABLED,

747client->name,(void*)chan);

748

749local_irq_save(flags);

750

751if(err){

752chan->in_use=0;

75

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 经管营销 > 经济市场

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1