PXA/MMP - DMA 从控制器

约束

a) 传输热排队:提交传输并发出传输指令的驱动程序应被保证即使在正在运行的 DMA 通道上也能将传输排队。这意味着排队不会等待上一次传输结束,并且描述符链接不仅仅在传输结束触发的 irq/tasklet 代码中完成。在物理通道上提交并发出的传输不会等待物理通道停止并重新启动,而是在“正在运行的通道”上提交。其他驱动程序,特别是 mmp_pdma,在重新启动新传输之前会等待物理通道停止。

b) 所有请求确认的传输都应发出信号:任何发出 DMA_PREP_INTERRUPT 的传输都应触发回调调用。这意味着,即使 irq/tasklet 是由 tx1 结束触发的,但在 irq/dma 时 tx2 已经完成,也应调用 tx1->complete() 和 tx2->complete()。

c) 通道运行状态:驱动程序应该能够查询通道是否正在运行。对于多媒体情况,例如视频捕获,如果提交传输后检查 DMA 通道报告“停止通道”,则不应发出传输,直到下一个“帧开始中断”,因此需要知道通道处于运行状态还是停止状态。

d) 带宽保证:PXA 架构有 4 个级别的 DMA 优先级:高、正常、低。高优先级获得的带宽是正常的两倍,而正常优先级获得的带宽是低优先级的两倍。驱动程序应该能够请求优先级,特别是像 pxa_camera 这样具有(大)吞吐量的实时驱动程序。

设计

a) 虚拟通道:与 sa11x0 驱动程序中的概念相同,即为驱动程序分配一个链接到请求器线路的“虚拟通道”,并且在发出传输时动态分配物理 DMA 通道。

  1. 分散-聚集传输的传输结构

+------------+-----+---------------+----------------+-----------------+
| desc-sg[0] | ... | desc-sg[last] | status updater | finisher/linker |
+------------+-----+---------------+----------------+-----------------+

此结构由 dma->sg_cpu 指向。描述符的使用方式如下

  • desc-sg[i]:第 i 个描述符,将第 i 个 sg 元素传输到视频缓冲区分散聚集

  • 状态更新程序:将单个 u32 传输到众所周知的 DMA 连贯内存,以留下此传输已完成的痕迹。“众所周知”对于每个物理通道都是唯一的,这意味着读取此值将告诉您此时最后一个完成的传输是哪个。

  • 完成器:具有 ddadr=DADDR_STOP,dcmd=ENDIRQEN

  • 链接器:具有下一个传输的 ddadr= desc-sg[0],dcmd=0

c) 传输热链接:假设正在运行的链是

Buffer 1              Buffer 2
+---------+----+---+  +----+----+----+---+
| d0 | .. | dN | l |  | d0 | .. | dN | f |
+---------+----+-|-+  ^----+----+----+---+
                 |    |
                 +----+

在调用 dmaengine_submit(b3) 后,链将如下所示

Buffer 1              Buffer 2              Buffer 3
+---------+----+---+  +----+----+----+---+  +----+----+----+---+
| d0 | .. | dN | l |  | d0 | .. | dN | l |  | d0 | .. | dN | f |
+---------+----+-|-+  ^----+----+----+-|-+  ^----+----+----+---+
                 |    |                |    |
                 +----+                +----+
                                      new_link

如果在创建 new_link 时 DMA 通道停止,则 _不_ 重新启动。热链接不会破坏 dma_async_issue_pending() 用于确保传输实际启动的假设。

此规则的一个例外情况

  • 如果 Buffer1 和 Buffer2 的所有地址都是 8 字节对齐的

  • 并且如果 Buffer3 至少有一个地址不是 4 字节对齐的

  • 则无法进行热链接,因为必须停止通道,必须设置“对齐位”,并且必须重新启动通道。因此,此类传输 tx_submit() 将在已提交队列中排队,并且如果 DMA 已经在对齐模式下运行,则属于此特定情况。

d) 传输完成更新程序:每次通道上的传输完成时,可能会或可能不会根据客户端的请求生成中断。但在每种情况下,传输的最后一个描述符(即“状态更新程序”)会将最新完成的传输写入物理通道的完成标记中。

这将加快残余计算,对于像视频缓冲区这样拥有大约 6k 或更多描述符的大型传输。这也允许在没有任何锁定的情况下找出正在运行的 DMA 链中最新完成的传输是什么。

e) 传输完成、irq 和 tasklet:当标记为“DMA_PREP_INTERRUPT”的传输完成时,会引发 dma irq。在此中断后,会为物理通道调度一个 tasklet。

tasklet 负责

  • 读取物理通道最后一个更新程序的标记

  • 根据该标记和每个传输标志,调用已完成传输的所有传输回调。

如果在此处理完成时传输完成,则将引发 dma irq,并且 tasklet 将再次调度,并具有新的更新程序标记。

f) 残余:残余粒度将基于描述符。将扫描已发出但未完成的传输,以查找其所有描述符与当前正在运行的描述符的对比情况。

g) 驱动程序的 tx 队列最复杂的情况:最棘手的情况是当

  • 没有“已确认”的传输 (tx0)

  • 驱动程序提交了未链接的对齐 tx1

  • 驱动程序提交了对齐的 tx2 => tx2 冷链接到 tx1

  • 驱动程序发出 tx1+tx2 => 通道以对齐模式运行

  • 驱动程序提交了对齐的 tx3 => tx3 热链接

  • 驱动程序提交了未对齐的 tx4 => tx4 被放入已提交队列,未链接

  • 驱动程序发出 tx4 => tx4 被放入已发出队列,未链接

  • 驱动程序提交了对齐的 tx5 => tx5 被放入已提交队列,未链接

  • 驱动程序提交了对齐的 tx6 => tx6 被放入已提交队列,冷链接到 tx5

这转换为(在发出 tx4 后)

  • 已发出队列

+-----+ +-----+ +-----+ +-----+
| tx1 | | tx2 | | tx3 | | tx4 |
+---|-+ ^---|-+ ^-----+ +-----+
    |   |   |   |
    +---+   +---+
  - submitted queue
+-----+ +-----+
| tx5 | | tx6 |
+---|-+ ^-----+
    |   |
    +---+
  • 已完成队列:空

  • 已分配队列:tx0

应该注意的是,在 tx3 完成后,通道停止,并以“未对齐模式”重新启动以处理 tx4。

作者:Robert Jarzmik <robert.jarzmik@free.fr>