Linux DMA API:指定地址增量行为?
Linux DMA API: specifying address increment behavior?
我正在为 Altera Soc Developement Kit 编写驱动程序,需要支持两种数据传输模式 to/from FPGA:
- FIFO 传输:写入(或读取)FPGA FIFO 时,目标(或源)地址不得由 DMA 控制器递增。
- 非 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 来指定地址递增行为。
这意味着以下内容:
- 指定方向=DMA_MEM_TO_DEV表示客户端希望将数据从FIFO 拉入RAM。大概 DMA_DEV_TO_MEM 意味着客户端希望将数据从 RAM 推入 FIFO。
- 分散-聚集 DMA 操作(至少对于 pl300)仅限于源端点或目标端点是 FIFO 的情况。如果我想执行从系统 RAM 到 FPGA(非 FIFO)内存的分散-聚集操作怎么办?
我是不是误会了 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_sg
和device_prep_dma_cyclic
声明
另一个选项应该是使用 and struct dma_interleaved_template
,它允许您直接指定增量行为。但是对这种方法的支持是有限的(例如,只有 i.MX DMA 驱动程序在 3.8 内核中支持它。甚至这种支持似乎也是有限的)
所以我认为,我们在 device_prep_slave_sg
案例中遇到了所有 sg
相关的复杂性一段时间。
这就是我目前正在做的事情(尽管它是为了访问 Atmel SAM9 SOC 上的一些 EBI 连接设备)
另一件需要考虑的事情是设备的总线宽度。 memcopy
-变体可以执行不同的总线宽度传输,具体取决于源和目标地址和大小。这可能与 FIFO 元素的大小不匹配。
我正在为 Altera Soc Developement Kit 编写驱动程序,需要支持两种数据传输模式 to/from FPGA:
- FIFO 传输:写入(或读取)FPGA FIFO 时,目标(或源)地址不得由 DMA 控制器递增。
- 非 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 来指定地址递增行为。
这意味着以下内容:
- 指定方向=DMA_MEM_TO_DEV表示客户端希望将数据从FIFO 拉入RAM。大概 DMA_DEV_TO_MEM 意味着客户端希望将数据从 RAM 推入 FIFO。
- 分散-聚集 DMA 操作(至少对于 pl300)仅限于源端点或目标端点是 FIFO 的情况。如果我想执行从系统 RAM 到 FPGA(非 FIFO)内存的分散-聚集操作怎么办?
我是不是误会了 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()
.
在我看来(在查看内核中的各种驱动程序之后)唯一允许您(间接)控制自动递增行为的 DMA 传输样式是在其对应的 device_prep_...
函数。
根据include/linux/dmaengine.h
device_prep_slave_sg
和device_prep_dma_cyclic
声明
另一个选项应该是使用 and struct dma_interleaved_template
,它允许您直接指定增量行为。但是对这种方法的支持是有限的(例如,只有 i.MX DMA 驱动程序在 3.8 内核中支持它。甚至这种支持似乎也是有限的)
所以我认为,我们在 device_prep_slave_sg
案例中遇到了所有 sg
相关的复杂性一段时间。
这就是我目前正在做的事情(尽管它是为了访问 Atmel SAM9 SOC 上的一些 EBI 连接设备)
另一件需要考虑的事情是设备的总线宽度。 memcopy
-变体可以执行不同的总线宽度传输,具体取决于源和目标地址和大小。这可能与 FIFO 元素的大小不匹配。