由于I2C是低速总线,其上传输的大部分消息都很小,因此不认为它是DMA访问的主要用户。在撰写本文时,只有10%的I2C总线master驱动程序实现了DMA支持。而且绝大多数事务都很小,因此为其设置DMA可能会比普通的PIO传输增加更多的开销。
因此,并不强制要求I2C消息的缓冲区是DMA安全的。当这个功能很少被使用时,施加额外的负担似乎是不合理的。但是,如果您的消息大小可能适用于DMA,建议使用DMA-safe的缓冲区。大多数驱动程序在8字节左右有这个阈值(然而,到目前为止,这主要是一种有根据的猜测)。对于任何16字节或更大的消息,这可能是一个非常好的主意。请注意,您使用的其他子系统可能会增加需求。例如,如果您的I2C总线主驱动程序使用USB作为桥接,那么您总是需要DMA安全缓冲区,因为USB需要它。
Clients
对于客户端,如果在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标志。
Masters
希望实现安全DMA的总线 master 驱动程序可以使用来自I2C核心的帮助函数。一种是为给定的i2c_msg提供dma安全缓冲区,只要满足特定的阈值:
dma_buf = i2c_get_dma_safe_msg_buf(msg, threshold_in_byte);
如果返回一个缓冲区,对于I2C_M_DMA_SAFE情况,它要么是msg->buf,要么是一个bounce缓冲区。但您不需要关心这些细节,只需使用返回的缓冲区。如果返回NULL,则表示阈值未满足或无法分配bounce缓冲区。在这种情况下,回到PIO。
在任何情况下,从上面获得的缓冲区都需要被释放。另一个帮助函数确保释放可能使用的bounce缓冲区:
i2c_put_dma_safe_msg_buf(dma_buf, msg, xferred);
最后一个参数' xferred '控制缓冲区是否被同步回消息。如果设置DMA出错且没有传输数据,则不需要同步。
来自核心的bounce缓冲区处理是通用和简单的。它总是会分配一个新的bounce缓冲区。如果你想要更复杂的处理方法(例如,重用预先分配的缓冲区),你可以自由地实现你自己的。有关详细信息,还请查看内核文档。i2c-sh_mobile驱动程序可以用作如何使用上述帮助程序的参考示例。
最后注意:如果您计划在I2C中使用DMA(或者实际上是其他任何东西),请确保在开发期间启用了CONFIG_DMA_API_DEBUG。它可以帮助您找到各种问题,这些问题在调试时可能很复杂。