在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
由于在传输大块数据的过程中无须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)(int, void *, 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)(int, void *, 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)
该函数是DMA中断处理函数的总入口,它在一个循环中检查所有DMA通道,如果对应通道发生中断,而且有人注册了该通道,它则调用注册的中断处理函数。如果没有人注册该通道,它就重置对应的DCSR寄存器。
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
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寄存器,比如DCSR、DINT、DRCMR和DDADR等。
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操作可以独立于具体硬件平台,这样驱动程序具有更好的可移植性,但不清楚什么原因,marvell的DMA实现并没有按照这个标准的方式去做。ARM对DMA的抽象如下:
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 */ 全部评论
专题导读
上一篇:ExplainingDelegatesinC#-Part5(AsynchronousCallback-Way2)发布时间:2022-07-14下一篇:C#调用c++数据类型对应发布时间:2022-07-14热门推荐
热门话题
阅读排行榜
|
请发表评论