最新消息:20210816 当前crifan.com域名已被污染,为防止失联,请关注(页面右下角的)公众号

Marvell-linux研究—dma.c源代码分析-1

工作和技术 crifan 1575浏览 0评论

Marvell-linux研究—dma.c源代码分析-1

转载时请注明出处和作者联系方式:http://blog.csdn.net/absurd

作者联系方式:李先静 <xianjimli at hotmail dot com>

更新时间:2007-7-16

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

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

31 static struct dma_channel {
32         char *name;
33         void (*irq_handler)(int, void *, struct pt_regs *);
34         void *data;
35 } dma_channels[PXA_DMA_CHANNELS];

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

38 int pxa_request_dma (char *name, pxa_dma_prio prio,
39                          void (*irq_handler)(int, void *, struct pt_regs *),
40                          void *data)
41 {
42         unsigned long flags;
43         int i, found = 0;
44
45         /* basic sanity checks */
46         if (!name || !irq_handler)
47                 returnEINVAL;
48
49          local_irq_save(flags);
50
51         /* try grabbing a DMA channel with the requested priority */
52         for (i = prio; i < prio + PXA_DMA_NBCH(prio); i++) {
53                 if (!dma_channels[i].name) {
54                          found = 1;
55                         break;
56                  }
57          }
58
59         if (!found) {
60                 /* requested prio group is full, try hier priorities */
61                 for (i = prio-1; i >= 0; i–) {
62                         if (!dma_channels[i].name) {
63                                  found = 1;
64                                 break;
65                          }
66                  }
67          }
68
69         if (found) {
70                  DCSR(i) = DCSR_STARTINTR|DCSR_ENDINTR|DCSR_BUSERR;
71                  dma_channels[i].name = name;
72                  dma_channels[i].irq_handler = irq_handler;
73                  dma_channels[i].data = data;
74          } else {
75                  printk (KERN_WARNING "No more available DMA channels for %sn", name);
76                  i = –ENODEV;
77          }
78
79          local_irq_restore(flags);
80         return i;
81 }

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

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

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

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

83 void pxa_free_dma (int dma_ch)
84 {
85         unsigned long flags;
86
87         if (!dma_channels[dma_ch].name) {
88                  printk (KERN_CRIT
89                         "%s: trying to free channel %d which is already freedn",
90                          __FUNCTION__, dma_ch);
91                 return;
92          }
93
94          local_irq_save(flags);
95          DCSR(dma_ch) = DCSR_STARTINTR|DCSR_ENDINTR|DCSR_BUSERR;
96          dma_channels[dma_ch].name = NULL;
97          local_irq_restore(flags);
98 }

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

100 static irqreturn_t dma_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
101 {
102         int i, dint = DINT;
103
104         for (i = 0; i < PXA_DMA_CHANNELS; i++) {
105                 if (dint & (1 << i)) {
106                         struct dma_channel *channel = &dma_channels[i];
107                         if (channel->name && channel->irq_handler) {
108                                  channel->irq_handler(i, channel->data, regs);
109                          } else {
110                                 /*
111                                  * IRQ for an unregistered DMA channel:
112                                  * let’s clear the interrupts and disable it.
113                                  */
114                                  printk (KERN_WARNING "spurious IRQ for DMA channel %dn", i);
115                                  DCSR(i) = DCSR_STARTINTR|DCSR_ENDINTR|DCSR_BUSERR;
116                          }
117                  }
118          }
119         return IRQ_HANDLED;
120 }

该函数是DMA中断处理函数的总入口,它在一个循环中检查所有DMA通道,如果对应通道发生中断,而且有人注册了该通道,它则调用注册的中断处理函数。如果没有人注册该通道,它就重置对应的DCSR寄存器。

123 void mhn_init_dmac(void)
124 {
125         int i;
126
127         for (i = 0; i < PXA_DMA_CHANNELS; i++) {
128                 /* clear all write-1-to-clear bits */
129                  DCSR(i) |= (DCSR_BUSERR | DCSR_STARTINTR | DCSR_ENDINTR |
130                                  DCSR_RASINTR | DCSR_EORINTR);
131                  DCSR(i) = 0x0;
132          }
133
134          DINT = 0;
135
136         /* clear DRCMR0 ~ DRCMR63 */
137         for (i = 0; i < 64; i++)
138                  DRCMR(i) = 0x0;
139
140         /* clear DRCMR64 ~ DRCMR99 */
141         for (i = 0; i < 36; i++)
142                  *((volatile uint32_t *)&DRCMR64 + i) = 0x0;
143
144         /* clear all the 32 DMA descriptors */
145         for (i = 0; i < 32 * 4; i++)
146                  *((volatile uint32_t *)&DDADR0 + i) = 0x0;
147 }

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

150 static int __init pxa_dma_init (void)
151 {
152         int ret;
153
154          ret = request_irq (IRQ_DMA, dma_irq_handler, 0, "DMA", NULL);
155         if (ret)
156                  printk (KERN_CRIT "Wow!   Can’t register IRQ for DMAn");
157         return ret;
158 }

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

转载请注明:在路上 » Marvell-linux研究—dma.c源代码分析-1

发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
79 queries in 0.196 seconds, using 22.19MB memory