PXA/MMP - DMA 从设备控制器¶
约束¶
a) 传输热队列:驱动程序提交传输并发出它,即使在运行的 DMA 通道上,也应保证该传输已排队。 这意味着排队不会等待上一次传输结束,并且描述符链接不仅在传输结束触发的 irq/tasklet 代码中完成。 在 phy 上提交和发出的传输不会等待 phy 停止并重新启动,而是在“运行通道”上提交。 其他驱动程序,尤其是 mmp_pdma,在重新启动新的传输之前会等待 phy 停止。
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 通道在发出传输时动态分配。
用于散布-收集传输的传输解剖
+------------+-----+---------------+----------------+-----------------+
| desc-sg[0] | ... | desc-sg[last] | status updater | finisher/linker |
+------------+-----+---------------+----------------+-----------------+
此结构由 dma->sg_cpu 指向。 描述符的使用方式如下
desc-sg[i]:第 i 个描述符,将第 i 个 sg 元素传输到视频缓冲区散布收集
状态更新器:将单个 u32 传输到众所周知的 dma 一致性内存,以留下此传输已完成的痕迹。 “众所周知”对于每个物理通道都是唯一的,这意味着读取此值将告诉您此时完成的最后一个传输。
finisher: 具有 ddadr=DADDR_STOP, dcmd=ENDIRQEN
linker: 具有 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>