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

Linux DMA API: specifying address increment behavior?

我正在为 Altera Soc Developement Kit 编写驱动程序,需要支持两种数据传输模式 to/from FPGA:

  1. FIFO 传输:写入(或读取)FPGA FIFO 时,目标(或源)地址不得由 DMA 控制器递增。
  2. 非 FIFO 传输:这些是正常的(类似 RAM)传输,其中源地址和目标地址都需要为每个传输的字递增。

我使用的特定 DMA 控制器是 CoreLink DMA-330 DMA 控制器,其 Linux 驱动程序是 pl330.c (drivers/dma/pl330.c)。这个 DMA 控制器确实提供了一种在 "Fixed-address burst" 和 "Incrementing-address burst" 之间切换的机制(这些是我的 "FIFO transfers" 和 "non-FIFO transfers" 的同义词)。 pl330 驱动程序通过在 CCRn 寄存器中设置适当的位来指定它想要的行为

#define CC_SRCINC       (1 << 0)
#define CC_DSTINC       (1 << 14)

我的问题:我完全不清楚 pl330 的客户端(例如我的驱动程序)应该如何指定地址递增行为。

DMA engine client API says nothing about how to specify this while the DMA engine provider API 简单地说明:

Addresses pointing to RAM are typically incremented (or decremented) after each transfer. In case of a ring buffer, they may loop (DMA_CYCLIC). Addresses pointing to a device's register (e.g. a FIFO) are typically fixed.

没有详细说明地址类型是如何传递给提供者的(在我的例子中是 pl300 驱动程序)。

在pl330_prep_slave_sg方法中它做的:

 if (direction == DMA_MEM_TO_DEV) {                  
     desc->rqcfg.src_inc = 1;                        
     desc->rqcfg.dst_inc = 0;                        
     desc->req.rqtype = MEMTODEV;                    
     fill_px(&desc->px,                              
         addr, sg_dma_address(sg), sg_dma_len(sg));  
 } else {                                            
     desc->rqcfg.src_inc = 0;                        
     desc->rqcfg.dst_inc = 1;                        
     desc->req.rqtype = DEVTOMEM;                    
     fill_px(&desc->px,                              
         sg_dma_address(sg), addr, sg_dma_len(sg));  
 }    

之后,驱动程序使用 desc->rqcfg.src_inc 和 desc->rqcfg.dst_inc 来指定地址递增行为。

这意味着以下内容:

我是不是误会了 and/or 忽略了什么? 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_prep_dma_memcpy().

完成类似 RAM 的传输

在我看来(在查看内核中的各种驱动程序之后)唯一允许您(间接)控制自动递增行为的 DMA 传输样式是在其对应的 device_prep_...函数。

根据include/linux/dmaengine.h

,此参数仅为device_prep_slave_sgdevice_prep_dma_cyclic声明

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

所以我认为,我们在 device_prep_slave_sg 案例中遇到了所有 sg 相关的复杂性一段时间。

这就是我目前正在做的事情(尽管它是为了访问 Atmel SAM9 SOC 上的一些 EBI 连接设备)

另一件需要考虑的事情是设备的总线宽度。 memcopy-变体可以执行不同的总线宽度传输,具体取决于源和目标地址和大小。这可能与 FIFO 元素的大小不匹配。