Marvell-linux研究—dma.c源代码分析-2
补充说明几点:
1. ARM平台对DMA操作做了一次抽象,它让DMA操作可以独立于具体硬件平台,这样驱动程序具有更好的可移植性,但不清楚什么原因,marvell的DMA实现并没有按照这个标准的方式去做。ARM对DMA的抽象如下:
struct dma_ops { int (*request)(dmach_t, dma_t *); /* optional */ void (*free)(dmach_t, dma_t *); /* optional */ void (*enable)(dmach_t, dma_t *); /* mandatory */ void (*disable)(dmach_t, dma_t *); /* mandatory */ int (*residue)(dmach_t, dma_t *); /* optional */ int (*setspeed)(dmach_t, dma_t *, int); /* optional */ char *type; }; struct dma_struct { struct scatterlist buf; /* single DMA */ int sgcount; /* number of DMA SG */ struct scatterlist *sg; /* DMA Scatter-Gather List */ unsigned int active:1; /* Transfer active */ unsigned int invalid:1; /* Address/Count changed */ unsigned int using_sg:1; /* using scatter list? */ dmamode_t dma_mode; /* DMA mode */ int speed; /* DMA speed */ unsigned int lock; /* Device is allocated */ const char *device_id; /* Device name */ unsigned int dma_base; /* Controller base address */ int dma_irq; /* Controller IRQ */ struct scatterlist cur_sg; /* Current controller buffer */ unsigned int state; struct dma_ops *d_ops; }; |
2. 前面的代码没有涉及DMA的使用方法,这里我们看一段串口中代码,以补其不足。
672 static void pxa_uart_receive_dma_start(struct uart_pxa_port *up) 673 { 674 dbg("enter"); 675 DCSR(up->rxdma) = DCSR_NODESC;// | DCSR_EORSTOPEN | DCSR_EORIRQEN; 676 DSADR(up->rxdma) = up->port.mapbase; 677 DTADR(up->rxdma) = up->rxdma_addr_phys; 678 DCMD(up->rxdma) = DCMD_INCTRGADDR | DCMD_FLOWSRC | DCMD_ENDIRQEN | DCMD_WIDTH1 | DCMD_BURST16 | DMA_BLOCK; 679 DCSR(up->rxdma) |= DCSR_RUN; 680 dbg("exit"); 681 } |
675在marvell平台上,DMA有两种工作方式,一种可以传输多个不连续地址的buffer,称之为描述符方式传输。另外一种一次只能传输一个buffer,称为非描述符方式。这里设置为非描述符方式。
676 设置源地址,其为串口的FIFO。
677 设置目标地址,其为物理内存地址。
678 设置命令寄存器。目标地址是内存,所以要加上DCMD_INCTRGADDR标志要求自动增加目标地址。而源地址是FIFO不需要显式的改变地址,所以不需要设置DCMD_INCSRCADDR标志。目标地址是内存,所以无需要流控。而源地址是FIFO,所以要设置源端流控DCMD_FLOWSRC标志。DCMD_ENDIRQEN标志允许传输完成时发现中断,DCMD_WIDTH1指明一个字节宽度,DCMD_BURST16指明一次传输16个字节,DMA_BLOCK指明传输数据的长度。
679 启动传输。
951 if (0 == up->rxdma) { 952 up->rxdma = 953 pxa_request_dma(up->name, DMA_PRIO_LOW, pxa_uart_receive_dma, up); 954 if (up->rxdma < 0) 955 goto out; 956 } 971 if (NULL == up->rxdma_addr) { 972 up->rxdma_addr = dma_alloc_coherent(NULL, DMA_BLOCK, &up->rxdma_addr_phys, GFP_KERNEL); 973 if (!up->rxdma_addr) 974 goto rxdma_err_alloc; 975 } |
951-956 注册DMA通道,pxa_uart_receive_dma为中断处理函数。
971-975 分配用于DMA传输的内存。
~~end~~
转载请注明:在路上 » Marvell-linux研究—dma.c源代码分析-2
Post Views: 5,563