Linux I2C 故障注入

基于 GPIO 的 I2C 总线主控驱动程序可以配置为提供故障注入功能。然后,它应该连接到另一个 I2C 总线,该总线由被测 I2C 总线主控驱动程序驱动。GPIO 故障注入驱动程序可以在总线上创建特殊状态,其他 I2C 总线主控驱动程序应优雅地处理这些状态。

一旦启用了 Kconfig 选项 I2C_GPIO_FAULT_INJECTOR,内核 debugfs 文件系统中将存在一个 “i2c-fault-injector” 子目录,通常挂载在 /sys/kernel/debug。每个 GPIO 驱动的 I2C 总线都有一个单独的子目录。每个子目录都包含触发故障注入的文件。现在将描述它们及其预期用例。

线路状态

“scl”

通过读取此文件,您可以获得 SCL 的当前状态。通过写入,您可以将其状态更改为强制拉低或再次释放。因此,通过使用 “echo 0 > scl” 您强制 SCL 为低电平,因此不可能进行通信,因为被测总线主控将无法进行时钟。它应该检测到 SCL 无响应的情况,并向高层报告错误。

“sda”

通过读取此文件,您可以获得 SDA 的当前状态。通过写入,您可以将其状态更改为强制拉低或再次释放。因此,通过使用 “echo 0 > sda” 您强制 SDA 为低电平,因此无法传输数据。被测总线主控应检测到此情况,并使用 Linux I2C 核心的辅助函数触发总线恢复(请参阅 I2C 规范版本 4,第 3.1.16 节)(请参阅 “struct bus_recovery_info”)。但是,总线恢复不会成功,因为 SDA 仍然被拉低,直到您使用 “echo 1 > sda” 手动释放它。可以使用 “不完整的传输” 类别的故障注入器进行自动释放测试。

不完整的传输

以下故障注入器会创建 SDA 被设备保持低电平的情况。总线恢复应该能够解决这些情况。但请注意:有些 I2C 客户端设备会检测到它们侧面的 SDA 卡住,并在几毫秒后自行释放。此外,可能存在外部设备去毛刺并监控 I2C 总线。它也可以检测到 SDA 卡住,并自行启动总线恢复。如果要在总线主控驱动程序中实现总线恢复,请确保事先检查硬件设置中是否存在此类设备。并始终使用示波器或逻辑分析仪进行验证!

“incomplete_address_phase”

此文件为只写,您需要向其中写入现有 I2C 客户端设备的地址。然后,将启动对此设备的读取传输,但它将在传输客户端地址后的 ACK 阶段停止。由于设备将 ACK 其存在,这会导致在 SCL 为高电平时,SDA 被设备拉低。因此,与上面的 “sda” 文件类似,被测总线主控应检测到此情况并尝试进行总线恢复。但是,这次它应该成功,并且设备应该在切换 SCL 后释放 SDA。

“incomplete_write_byte”

与上面类似,此文件为只写,您需要向其中写入现有 I2C 客户端设备的地址。

注入器将再次在一个 ACK 阶段停止,因此设备将保持 SDA 为低电平,因为它确认了数据。但是,与 “incomplete_address_phase” 相比,有两个区别

  1. 发送的消息将是写消息

  2. 在地址字节之后,将传输一个 0x00 字节。然后,在 ACK 处停止。

这是一个高度微妙的状态,当 SCL 上发生进一步的时钟脉冲时,该设备被设置为将任何数据写入寄存器 0x00(如果它有寄存器)。这就是为什么总线恢复(最多 9 个时钟脉冲)必须检查 SDA 或发送额外的 STOP 条件,以确保总线已释放。否则,随机数据将被写入设备!

仲裁丢失

在这里,我们要模拟被测主控在多主控设置中丢失与另一个主控的总线仲裁的情况。

“lose_arbitration”

此文件为只写,您需要写入仲裁干扰的持续时间(以微秒为单位,最大值为 100 毫秒)。然后,调用进程将休眠并等待下一个总线时钟。但是,该进程是可中断的。

仲裁丢失是通过等待被测主控使 SCL 下降,然后将 SDA 拉低一段时间来实现的。因此,发送的 I2C 地址应被破坏,并且应正确检测到这一点。这意味着发送的地址应有很多“1”位才能检测到损坏。此地址不需要有设备,因为应事先检测到仲裁丢失。另请注意,SCL 下降是使用中断进行监控的,因此中断延迟可能会导致前几个位未被破坏。在空闲总线上使用此故障注入器的一个好的起点是

# echo 200 > lose_arbitration &
# i2cget -y <bus_to_test> 0x3f

传输期间发生内核恐慌

一旦被测主控开始传输,此故障注入器将创建一个内核恐慌。这通常意味着总线主控驱动程序的状态机将被不正常地中断,并且总线可能会最终处于不寻常的状态。使用此方法来检查您的关闭/重启/启动代码是否可以处理这种情况。

“inject_panic”

此文件为只写,您需要写入检测到传输开始和引发内核恐慌之间的延迟(以微秒为单位,最大值为 100 毫秒)。然后,调用进程将休眠并等待下一个总线时钟。但是,该进程是可中断的。

通过等待被测主控使 SCL 下降来检测传输的开始。在空闲总线上使用此故障注入器的一个好的起点是

# echo 0 > inject_panic &
# i2cget -y <bus_to_test> <some_address>

请注意,不需要有设备监听您正在使用的地址。但是,结果可能会因情况而异。