162306a36Sopenharmony_ci========================= 262306a36Sopenharmony_ciLinux I2C fault injection 362306a36Sopenharmony_ci========================= 462306a36Sopenharmony_ci 562306a36Sopenharmony_ciThe GPIO based I2C bus master driver can be configured to provide fault 662306a36Sopenharmony_ciinjection capabilities. It is then meant to be connected to another I2C bus 762306a36Sopenharmony_ciwhich is driven by the I2C bus master driver under test. The GPIO fault 862306a36Sopenharmony_ciinjection driver can create special states on the bus which the other I2C bus 962306a36Sopenharmony_cimaster driver should handle gracefully. 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ciOnce the Kconfig option I2C_GPIO_FAULT_INJECTOR is enabled, there will be an 1262306a36Sopenharmony_ci'i2c-fault-injector' subdirectory in the Kernel debugfs filesystem, usually 1362306a36Sopenharmony_cimounted at /sys/kernel/debug. There will be a separate subdirectory per GPIO 1462306a36Sopenharmony_cidriven I2C bus. Each subdirectory will contain files to trigger the fault 1562306a36Sopenharmony_ciinjection. They will be described now along with their intended use-cases. 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ciWire states 1862306a36Sopenharmony_ci=========== 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci"scl" 2162306a36Sopenharmony_ci----- 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ciBy reading this file, you get the current state of SCL. By writing, you can 2462306a36Sopenharmony_cichange its state to either force it low or to release it again. So, by using 2562306a36Sopenharmony_ci"echo 0 > scl" you force SCL low and thus, no communication will be possible 2662306a36Sopenharmony_cibecause the bus master under test will not be able to clock. It should detect 2762306a36Sopenharmony_cithe condition of SCL being unresponsive and report an error to the upper 2862306a36Sopenharmony_cilayers. 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci"sda" 3162306a36Sopenharmony_ci----- 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ciBy reading this file, you get the current state of SDA. By writing, you can 3462306a36Sopenharmony_cichange its state to either force it low or to release it again. So, by using 3562306a36Sopenharmony_ci"echo 0 > sda" you force SDA low and thus, data cannot be transmitted. The bus 3662306a36Sopenharmony_cimaster under test should detect this condition and trigger a bus recovery (see 3762306a36Sopenharmony_ciI2C specification version 4, section 3.1.16) using the helpers of the Linux I2C 3862306a36Sopenharmony_cicore (see 'struct bus_recovery_info'). However, the bus recovery will not 3962306a36Sopenharmony_cisucceed because SDA is still pinned low until you manually release it again 4062306a36Sopenharmony_ciwith "echo 1 > sda". A test with an automatic release can be done with the 4162306a36Sopenharmony_ci"incomplete transfers" class of fault injectors. 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ciIncomplete transfers 4462306a36Sopenharmony_ci==================== 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ciThe following fault injectors create situations where SDA will be held low by a 4762306a36Sopenharmony_cidevice. Bus recovery should be able to fix these situations. But please note: 4862306a36Sopenharmony_cithere are I2C client devices which detect a stuck SDA on their side and release 4962306a36Sopenharmony_ciit on their own after a few milliseconds. Also, there might be an external 5062306a36Sopenharmony_cidevice deglitching and monitoring the I2C bus. It could also detect a stuck SDA 5162306a36Sopenharmony_ciand will init a bus recovery on its own. If you want to implement bus recovery 5262306a36Sopenharmony_ciin a bus master driver, make sure you checked your hardware setup for such 5362306a36Sopenharmony_cidevices before. And always verify with a scope or logic analyzer! 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci"incomplete_address_phase" 5662306a36Sopenharmony_ci-------------------------- 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ciThis file is write only and you need to write the address of an existing I2C 5962306a36Sopenharmony_ciclient device to it. Then, a read transfer to this device will be started, but 6062306a36Sopenharmony_ciit will stop at the ACK phase after the address of the client has been 6162306a36Sopenharmony_citransmitted. Because the device will ACK its presence, this results in SDA 6262306a36Sopenharmony_cibeing pulled low by the device while SCL is high. So, similar to the "sda" file 6362306a36Sopenharmony_ciabove, the bus master under test should detect this condition and try a bus 6462306a36Sopenharmony_cirecovery. This time, however, it should succeed and the device should release 6562306a36Sopenharmony_ciSDA after toggling SCL. 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci"incomplete_write_byte" 6862306a36Sopenharmony_ci----------------------- 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ciSimilar to above, this file is write only and you need to write the address of 7162306a36Sopenharmony_cian existing I2C client device to it. 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ciThe injector will again stop at one ACK phase, so the device will keep SDA low 7462306a36Sopenharmony_cibecause it acknowledges data. However, there are two differences compared to 7562306a36Sopenharmony_ci'incomplete_address_phase': 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_cia) the message sent out will be a write message 7862306a36Sopenharmony_cib) after the address byte, a 0x00 byte will be transferred. Then, stop at ACK. 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ciThis is a highly delicate state, the device is set up to write any data to 8162306a36Sopenharmony_ciregister 0x00 (if it has registers) when further clock pulses happen on SCL. 8262306a36Sopenharmony_ciThis is why bus recovery (up to 9 clock pulses) must either check SDA or send 8362306a36Sopenharmony_ciadditional STOP conditions to ensure the bus has been released. Otherwise 8462306a36Sopenharmony_cirandom data will be written to a device! 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ciLost arbitration 8762306a36Sopenharmony_ci================ 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ciHere, we want to simulate the condition where the master under test loses the 9062306a36Sopenharmony_cibus arbitration against another master in a multi-master setup. 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci"lose_arbitration" 9362306a36Sopenharmony_ci------------------ 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ciThis file is write only and you need to write the duration of the arbitration 9662306a36Sopenharmony_ciinterference (in µs, maximum is 100ms). The calling process will then sleep 9762306a36Sopenharmony_ciand wait for the next bus clock. The process is interruptible, though. 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ciArbitration lost is achieved by waiting for SCL going down by the master under 10062306a36Sopenharmony_citest and then pulling SDA low for some time. So, the I2C address sent out 10162306a36Sopenharmony_cishould be corrupted and that should be detected properly. That means that the 10262306a36Sopenharmony_ciaddress sent out should have a lot of '1' bits to be able to detect corruption. 10362306a36Sopenharmony_ciThere doesn't need to be a device at this address because arbitration lost 10462306a36Sopenharmony_cishould be detected beforehand. Also note, that SCL going down is monitored 10562306a36Sopenharmony_ciusing interrupts, so the interrupt latency might cause the first bits to be not 10662306a36Sopenharmony_cicorrupted. A good starting point for using this fault injector on an otherwise 10762306a36Sopenharmony_ciidle bus is:: 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci # echo 200 > lose_arbitration & 11062306a36Sopenharmony_ci # i2cget -y <bus_to_test> 0x3f 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ciPanic during transfer 11362306a36Sopenharmony_ci===================== 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ciThis fault injector will create a Kernel panic once the master under test 11662306a36Sopenharmony_cistarted a transfer. This usually means that the state machine of the bus master 11762306a36Sopenharmony_cidriver will be ungracefully interrupted and the bus may end up in an unusual 11862306a36Sopenharmony_cistate. Use this to check if your shutdown/reboot/boot code can handle this 11962306a36Sopenharmony_ciscenario. 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci"inject_panic" 12262306a36Sopenharmony_ci-------------- 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ciThis file is write only and you need to write the delay between the detected 12562306a36Sopenharmony_cistart of a transmission and the induced Kernel panic (in µs, maximum is 100ms). 12662306a36Sopenharmony_ciThe calling process will then sleep and wait for the next bus clock. The 12762306a36Sopenharmony_ciprocess is interruptible, though. 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ciStart of a transfer is detected by waiting for SCL going down by the master 13062306a36Sopenharmony_ciunder test. A good starting point for using this fault injector is:: 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci # echo 0 > inject_panic & 13362306a36Sopenharmony_ci # i2cget -y <bus_to_test> <some_address> 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ciNote that there doesn't need to be a device listening to the address you are 13662306a36Sopenharmony_ciusing. Results may vary depending on that, though. 137