Linux I2C 和 DMA¶
鑑於 I2C 是一種低速匯流排,其上傳輸的大多數訊息都很小,因此它不被認為是 DMA 訪問的主要使用者。 在撰寫本文時,只有 10% 的 I2C 匯流排主驅動程式實現了 DMA 支援。 而且絕大多數事務都很小,因此為其設定 DMA 可能會增加比普通 PIO 傳輸更多的開銷。
因此,*不是*強制要求 I2C 訊息的緩衝區是 DMA 安全的。 當該功能很少使用時,施加額外的負擔似乎是不合理的。 但是,如果您的訊息大小可能適用於 DMA,建議使用 DMA 安全的緩衝區。 大多數驅動程式將此閾值設定在 8 位元組左右(截至今天,這主要是一個有根據的猜測)。 對於任何 16 位元組或更大的訊息,這可能是一個非常好的主意。 請注意,您使用的其他子系統可能會新增要求。 例如,如果您的 I2C 匯流排主驅動程式使用 USB 作為橋接器,那麼您需要始終具有 DMA 安全的緩衝區,因為 USB 需要它。
客戶端¶
對於客戶端,如果您在 i2c_msg 中使用 DMA 安全緩衝區,請設定 I2C_M_DMA_SAFE 標誌。 然後,I2C 核心和驅動程式就知道它們可以安全地在其上操作 DMA。 請注意,使用此標誌是可選的。 未更新為使用此標誌的 I2C 主機驅動程式將像以前一樣工作。 並且像以前一樣,它們有使用不安全 DMA 緩衝區的風險。 為了改善這種情況,在越來越多的客戶端和主機驅動程式中使用 I2C_M_DMA_SAFE 是計劃中的前進方向。 另請注意,設定此標誌僅在核心空間中有意義。 使用者空間資料無論如何都會複製到核心空間。 I2C 核心確保核心空間中的目標緩衝區始終具有 DMA 功能。 此外,當核心透過 I2C 模擬 SMBus 事務時,塊傳輸的緩衝區是 DMA 安全的。 i2c_master_send() 和 i2c_master_recv() 函式的使用者現在可以使用 DMA 安全變體 (i2c_master_send_dmasafe() 和 i2c_master_recv_dmasafe()),一旦他們知道他們的緩衝區是 DMA 安全的。 i2c_transfer() 的使用者必須手動設定 I2C_M_DMA_SAFE 標誌。
主機¶
希望實現安全 DMA 的匯流排主驅動程式可以使用 I2C 核心中的輔助函式。 一個為您提供給定 i2c_msg 的 DMA 安全緩衝區,只要滿足某個閾值即可
dma_buf = i2c_get_dma_safe_msg_buf(msg, threshold_in_byte);
如果返回緩衝區,則對於 I2C_M_DMA_SAFE 情況,它是 msg->buf 或反彈緩衝區。 但是您不需要關心該細節,只需使用返回的緩衝區即可。 如果返回 NULL,則未滿足閾值或無法分配反彈緩衝區。 在這種情況下,回退到 PIO。
在任何情況下,都需要釋放從上面獲得的緩衝區。 另一個輔助函式確保釋放潛在使用的反彈緩衝區
i2c_put_dma_safe_msg_buf(dma_buf, msg, xferred);
最後一個引數“xferred”控制緩衝區是否同步回訊息。 如果設定 DMA 出錯並且沒有傳輸任何資料,則無需同步。
核心的反彈緩衝區處理是通用的且簡單的。 它將始終分配一個新的反彈緩衝區。 如果您想要更復雜的處理(例如,重用預先分配的緩衝區),您可以自由地實現自己的處理方式。
另請檢視核心文件以獲取詳細資訊。 i2c-sh_mobile 驅動程式可以用作如何使用上述輔助函式的參考示例。
最後的注意事項:如果您計劃將 DMA 與 I2C(或與任何其他東西)一起使用,請確保在開發期間啟用 CONFIG_DMA_API_DEBUG。 它可以幫助您找到各種問題,否則這些問題可能很難除錯。