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>