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 通道在發出傳輸時動態分配。

  1. 用於散佈-收集傳輸的傳輸解剖

+------------+-----+---------------+----------------+-----------------+
| 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>