Linux DMA驱动构架分析.docx
- 文档编号:11214312
- 上传时间:2023-02-25
- 格式:DOCX
- 页数:17
- 大小:21.88KB
Linux DMA驱动构架分析.docx
《Linux DMA驱动构架分析.docx》由会员分享,可在线阅读,更多相关《Linux DMA驱动构架分析.docx(17页珍藏版)》请在冰豆网上搜索。
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;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
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Linux DMA驱动构架分析 DMA 驱动 构架 分析