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

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

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

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

补充说明几点:

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

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 }

675marvell平台上,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

发表我的评论
取消评论

表情

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

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