• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

dma.c源代码分析

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

由于在传输大块数据的过程中无须CPU干预(当然在开始、出错和结束时仍然需要),所以与轮询和中断相比,DMA传输效率要高得多。另外,Marvell平台上提供了所谓的memory switch,总线有更高的利用率,DMA就更能显出它的优势了。

下面我们看看mach-pxa/dma.c中的代码:

1  31 static struct dma_channel {
2  32         char *name;
3  33         void (*irq_handler)(intvoid *struct pt_regs *);
4  34         void *data;
5  35 } dma_channels[PXA_DMA_CHANNELS];
6 

该结构用于保存已注册的DMA中断处理函数,成员name表示该通道的名称,它只是起说明的作用,没有什么实际用途。成员irq_handler是所注册的中断处理函数,当该通道发生中断时,该函数被调用。成员data是中断处理函数irq_handler的调用上下文,当中断处理函数被调用时,其作为第二个参数传入。

 1  38 int pxa_request_dma (char *name, pxa_dma_prio prio,
 2  39                          void (*irq_handler)(intvoid *struct pt_regs *),
 3  40                          void *data)
 4  41 {
 5  42         unsigned long flags;
 6  43         int i, found = 0;
 7  44 
 8  45         /* basic sanity checks */
 9  46         if (!name || !irq_handler)
10  47                 return -EINVAL;
11  48 
12  49         local_irq_save(flags);
13  50 
14  51         /* try grabbing a DMA channel with the requested priority */
15  52         for (i = prio; i < prio + PXA_DMA_NBCH(prio); i++) {
16  53                 if (!dma_channels[i].name) {
17  54                         found = 1;
18  55                         break;
19  56                 }
20  57         }
21  58 
22  59         if (!found) {
23  60                 /* requested prio group is full, try hier priorities */
24  61                 for (i = prio-1; i >= 0; i--) {
25  62                         if (!dma_channels[i].name) {
26  63                                 found = 1;
27  64                                 break;
28  65                         }
29  66                 }
30  67         }
31  68 
32  69         if (found) {
33  70                 DCSR(i) = DCSR_STARTINTR|DCSR_ENDINTR|DCSR_BUSERR;
34  71                 dma_channels[i].name = name;
35  72                 dma_channels[i].irq_handler = irq_handler;
36  73                 dma_channels[i].data = data;
37  74         } else {
38  75                 printk (KERN_WARNING "No more available DMA channels for %s\n", name);
39  76                 i = -ENODEV;
40  77         }
41  78 
42  79         local_irq_restore(flags);
43  80         return i;
44  81 }
45 

注册一个DMA通道,其参数有名称、优先级、中断处理函数和中断处理函数的调用上下文。

这里的优先级和开发手册中所说的略有差别,在开发手册中(11.3.1.1)里说,从硬件的角度,优先级分为四等,0等优先级最高,3等优先级最低。在代码中,优先级只分为高中低三等,高优先级和中优先级的通道数为8个,低优先级的通道数为16个。

dma_channels数组中,按优先级从高到低排列,在注册时,先看在所请求的优先级中是否有空位,如果有,就使用该空位,如果没有,就从更高优先级中去找,直到找一个空位,或者发现没有空位可用,则中断循环。

如果找到合适的空位,则重置该通道的状态。和我们前面几次分析中所提到的一样,70行中的代码并非是要设置DCSR_STARTINTR|DCSR_ENDINTR|DCSR_BUSERR几个位域,而是在对应的位域上写1去清除它。

 1  83 void pxa_free_dma (int dma_ch)
 2  84 {
 3  85         unsigned long flags;
 4  86 
 5  87         if (!dma_channels[dma_ch].name) {
 6  88                 printk (KERN_CRIT
 7  89                         "%s: trying to free channel %d which is already freed\n",
 8  90                         __FUNCTION__, dma_ch);
 9  91                 return;
10  92         }
11  93 
12  94         local_irq_save(flags);
13  95         DCSR(dma_ch) = DCSR_STARTINTR|DCSR_ENDINTR|DCSR_BUSERR;
14  96         dma_channels[dma_ch].name = NULL;
15  97         local_irq_restore(flags);
16  98 }
17 

该函数用于注销DMA通道,它重置对应的DCSR寄存器,并把name置空。

 1 100 static irqreturn_t dma_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
 2 101 {
 3 102         int i, dint = DINT;
 4 103 
 5 104         for (i = 0; i < PXA_DMA_CHANNELS; i++) {
 6 105                 if (dint & (1 << i)) {
 7 106                         struct dma_channel *channel = &dma_channels[i];
 8 107                         if (channel->name && channel->irq_handler) {
 9 108                                 channel->irq_handler(i, channel->data, regs);
10 109                         } else {
11 110                                 /*
12 111                                  * IRQ for an unregistered DMA channel:
13 112                                  * let's clear the interrupts and disable it.
14 113                                  */
15 114                                 printk (KERN_WARNING "spurious IRQ for DMA channel %d\n", i);
16 115                                 DCSR(i) = DCSR_STARTINTR|DCSR_ENDINTR|DCSR_BUSERR;
17 116                         }
18 117                 }
19 118         }
20 119         return IRQ_HANDLED;
21 120 }
22 
该函数是DMA中断处理函数的总入口,它在一个循环中检查所有DMA通道,如果对应通道发生中断,而且有人注册了该通道,它则调用注册的中断处理函数。如果没有人注册该通道,它就重置对应的DCSR寄存器。
 1 123 void mhn_init_dmac(void)
 2 124 {
 3 125         int i;
 4 126 
 5 127         for (i = 0; i < PXA_DMA_CHANNELS; i++) {
 6 128                 /* clear all write-1-to-clear bits */
 7 129                 DCSR(i) |= (DCSR_BUSERR | DCSR_STARTINTR | DCSR_ENDINTR |
 8 130                                 DCSR_RASINTR | DCSR_EORINTR);
 9 131                 DCSR(i) = 0x0;
10 132         }
11 133 
12 134         DINT = 0;
13 135 
14 136         /* clear DRCMR0 ~ DRCMR63 */
15 137         for (i = 0; i < 64; i++)
16 138                 DRCMR(i) = 0x0;
17 139 
18 140         /* clear DRCMR64 ~ DRCMR99 */
19 141         for (i = 0; i < 36; i++)
20 142                 *((volatile uint32_t *)&DRCMR64 + i) = 0x0;
21 143 
22 144         /* clear all the 32 DMA descriptors */
23 145         for (i = 0; i < 32 * 4; i++)
24 146                 *((volatile uint32_t *)&DDADR0 + i) = 0x0;
25 147 }
26 

该函数初始化所有通道的DMA寄存器,比如DCSRDINTDRCMRDDADR等。

 1 150 static int __init pxa_dma_init (void)
 2 151 {
 3 152         int ret;
 4 153 
 5 154         ret = request_irq (IRQ_DMA, dma_irq_handler, 0"DMA", NULL);
 6 155         if (ret)
 7 156                 printk (KERN_CRIT "Wow!  Can't register IRQ for DMA\n");
 8 157         return ret;
 9 158 }
10 

初始化DMA,向系统注册一个中断处理函数。

补充说明几点:

1.       ARM平台对DMA操作做了一次抽象,它让DMA操作可以独立于具体硬件平台,这样驱动程序具有更好的可移植性,但不清楚什么原因,marvellDMA实现并没有按照这个标准的方式去做。ARMDMA的抽象如下:

 

 1 struct dma_ops {
 2         int    (*request)(dmach_t, dma_t *);           /* optional */
 3         void   (*free)(dmach_t, dma_t *);              /* optional */
 4         void   (*enable)(dmach_t, dma_t *);            /* mandatory */
 5         void   (*disable)(dmach_t, dma_t *);           /* mandatory */
 6         int    (*residue)(dmach_t, dma_t *);           /* optional */
 7         int    (*setspeed)(dmach_t, dma_t *int);        /* optional */
 8         char   *type;
 9 };
10 
11 struct dma_struct {
12         struct scatterlist buf;                /* single DMA                 */
13         int            sgcount;        /* number of DMA SG              */
14         struct scatterlist *sg;                /* DMA Scatter-Gather List    */
15 
16         unsigned int   active:1/* Transfer active              */
17         unsigned int   invalid:1;        /* Address/Count changed       */
18         unsigned int   using_sg:1;       /* using scatter list?                */
19         dmamode_t       dma_mode;       /* DMA mode                        */
20         int            speed;          /* DMA speed                      */
21 
22         unsigned int   lock;           /* Device is allocated             */

鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
ExplainingDelegatesinC#-Part5(AsynchronousCallback-Way2)发布时间:2022-07-14
下一篇:
C#调用c++数据类型对应发布时间:2022-07-14
热门推荐
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap