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