Linux DMA API:指定地址增量行为?

Linux DMA API:指定地址增量行为?,linux,linux-kernel,dma,Linux,Linux Kernel,Dma,我正在为FPGA编写驱动程序,需要支持两种数据传输模式: FIFO传输:写入(或读取)FPGA FIFO时,DMA控制器不得增加目标(或源)地址 非FIFO传输:这是正常的(类似RAM的)传输,其中源地址和目标地址都要求传输的每个字都有一个增量 我使用的特定DMA控制器是CoreLink DMA-330 DMA控制器,其Linux驱动程序是pl330.c(drivers/DMA/pl330.c)。该DMA控制器提供了一种在“固定地址突发”和“递增地址突发”之间切换的机制(它们与我的“FIFO传输

我正在为FPGA编写驱动程序,需要支持两种数据传输模式:

  • FIFO传输:写入(或读取)FPGA FIFO时,DMA控制器不得增加目标(或源)地址
  • 非FIFO传输:这是正常的(类似RAM的)传输,其中源地址和目标地址都要求传输的每个字都有一个增量
  • 我使用的特定DMA控制器是CoreLink DMA-330 DMA控制器,其Linux驱动程序是pl330.c(drivers/DMA/pl330.c)。该DMA控制器提供了一种在“固定地址突发”和“递增地址突发”之间切换的机制(它们与我的“FIFO传输”和“非FIFO传输”同义)。pl330驱动程序通过在CCRn寄存器中设置适当的位来指定它想要的行为

    #define CC_SRCINC       (1 << 0)
    #define CC_DSTINC       (1 << 14)
    
    其中,驱动程序使用desc->rqcfg.src_inc和desc->rqcfg.dst_inc指定地址增量行为

    这意味着:

    • 指定direction=DMA_MEM_TO_DEV意味着客户端希望将数据从FIFO拉入RAM。大概DMA_DEV_TO_MEM意味着客户端希望将数据从RAM推送到FIFO中
    • 分散-聚集DMA操作(至少适用于pl300)仅限于源或目标端点为FIFO的情况。如果我想从系统RAM到FPGA(非FIFO)内存执行分散-聚集操作,该怎么办
    我是否误解和/或忽视了什么?DMA引擎是否已经提供了(未记录的)机制来指定地址增量行为?

    看看这个

    pd->device_prep_dma_memcpy = pl330_prep_dma_memcpy;
    pd->device_prep_dma_cyclic = pl330_prep_dma_cyclic;
    pd->device_prep_slave_sg = pl330_prep_slave_sg;
    
    这意味着你有不同的方法,就像你在文档中读到的那样。我怀疑,通过
    device\u prep\u dma\u memcpy()

    可以完成类似RAM的传输(在查看内核中的各种驱动程序后),我认为这是唯一允许您(间接地)进行dma传输的样式控制自动增量行为是在其相应的
    设备准备功能中具有
    枚举dma\u传输方向的行为

    根据
    include/linux/dmaengine.h

    另一个选项应该是使用和
    struct dma_interleaved_template
    ,它允许您直接指定增量行为。但对这种方法的支持是有限的(例如,在3.8内核中,只有i.MX DMA驱动程序支持它,甚至这种支持似乎也是有限的)

    因此,我认为,在一段时间内,我们一直在处理
    device\u prep\u slave\u sg
    案例以及所有与
    sg
    相关的复杂性

    这就是我目前正在做的(尽管它是用于访问Atmel SAM9 SOC上的某些EBI连接设备)


    另一件需要考虑的是设备的总线宽度。code>memcopy

    -根据源和目标地址和大小,variant可以执行不同的总线宽度传输。这可能与FIFO元素的大小不匹配。

    是的,我是通过阅读pl330驱动程序得到的。看起来我可以为这个特定的DMA控制器驱动程序指定地址增量行为(通过prep_DMA_memcpy()或prep_slave_sg()方法)。但这是所有DMA控制器驱动程序使用的约定吗?如果使用了新的DMA控制器驱动程序,我不希望我的DMA客户端驱动程序中断。您必须修复所有要使用的驱动程序。通用实现允许您使用有限的功能集。不同的DMA控制器行为不同,因此DMA信道的用户应该应对所有可能的情况。
    pd->device_prep_dma_memcpy = pl330_prep_dma_memcpy;
    pd->device_prep_dma_cyclic = pl330_prep_dma_cyclic;
    pd->device_prep_slave_sg = pl330_prep_slave_sg;