Wolfram Sang | 05bd072 | 2019-01-21 15:16:57 +0100 | [diff] [blame] | 1 | ========================= |
Wolfram Sang | 14911c6 | 2017-11-28 16:53:32 +0100 | [diff] [blame] | 2 | Linux I2C fault injection |
| 3 | ========================= |
| 4 | |
| 5 | The GPIO based I2C bus master driver can be configured to provide fault |
| 6 | injection capabilities. It is then meant to be connected to another I2C bus |
| 7 | which is driven by the I2C bus master driver under test. The GPIO fault |
| 8 | injection driver can create special states on the bus which the other I2C bus |
| 9 | master driver should handle gracefully. |
| 10 | |
| 11 | Once the Kconfig option I2C_GPIO_FAULT_INJECTOR is enabled, there will be an |
| 12 | 'i2c-fault-injector' subdirectory in the Kernel debugfs filesystem, usually |
| 13 | mounted at /sys/kernel/debug. There will be a separate subdirectory per GPIO |
| 14 | driven I2C bus. Each subdirectory will contain files to trigger the fault |
| 15 | injection. They will be described now along with their intended use-cases. |
| 16 | |
Wolfram Sang | 05bd072 | 2019-01-21 15:16:57 +0100 | [diff] [blame] | 17 | Wire states |
| 18 | =========== |
| 19 | |
Wolfram Sang | 14911c6 | 2017-11-28 16:53:32 +0100 | [diff] [blame] | 20 | "scl" |
| 21 | ----- |
| 22 | |
| 23 | By reading this file, you get the current state of SCL. By writing, you can |
| 24 | change its state to either force it low or to release it again. So, by using |
| 25 | "echo 0 > scl" you force SCL low and thus, no communication will be possible |
| 26 | because the bus master under test will not be able to clock. It should detect |
| 27 | the condition of SCL being unresponsive and report an error to the upper |
| 28 | layers. |
| 29 | |
| 30 | "sda" |
| 31 | ----- |
| 32 | |
| 33 | By reading this file, you get the current state of SDA. By writing, you can |
| 34 | change its state to either force it low or to release it again. So, by using |
| 35 | "echo 0 > sda" you force SDA low and thus, data cannot be transmitted. The bus |
| 36 | master under test should detect this condition and trigger a bus recovery (see |
| 37 | I2C specification version 4, section 3.1.16) using the helpers of the Linux I2C |
| 38 | core (see 'struct bus_recovery_info'). However, the bus recovery will not |
| 39 | succeed because SDA is still pinned low until you manually release it again |
| 40 | with "echo 1 > sda". A test with an automatic release can be done with the |
Wolfram Sang | 05bd072 | 2019-01-21 15:16:57 +0100 | [diff] [blame] | 41 | "incomplete transfers" class of fault injectors. |
Wolfram Sang | 14911c6 | 2017-11-28 16:53:32 +0100 | [diff] [blame] | 42 | |
Wolfram Sang | 05bd072 | 2019-01-21 15:16:57 +0100 | [diff] [blame] | 43 | Incomplete transfers |
| 44 | ==================== |
Wolfram Sang | 16d55da | 2018-06-29 11:12:46 +0200 | [diff] [blame] | 45 | |
| 46 | The following fault injectors create situations where SDA will be held low by a |
| 47 | device. Bus recovery should be able to fix these situations. But please note: |
| 48 | there are I2C client devices which detect a stuck SDA on their side and release |
| 49 | it on their own after a few milliseconds. Also, there might be an external |
| 50 | device deglitching and monitoring the I2C bus. It could also detect a stuck SDA |
| 51 | and will init a bus recovery on its own. If you want to implement bus recovery |
| 52 | in a bus master driver, make sure you checked your hardware setup for such |
| 53 | devices before. And always verify with a scope or logic analyzer! |
| 54 | |
| 55 | "incomplete_address_phase" |
| 56 | -------------------------- |
Wolfram Sang | 14911c6 | 2017-11-28 16:53:32 +0100 | [diff] [blame] | 57 | |
| 58 | This file is write only and you need to write the address of an existing I2C |
Wolfram Sang | 16d55da | 2018-06-29 11:12:46 +0200 | [diff] [blame] | 59 | client device to it. Then, a read transfer to this device will be started, but |
| 60 | it will stop at the ACK phase after the address of the client has been |
Wolfram Sang | 14911c6 | 2017-11-28 16:53:32 +0100 | [diff] [blame] | 61 | transmitted. Because the device will ACK its presence, this results in SDA |
| 62 | being pulled low by the device while SCL is high. So, similar to the "sda" file |
| 63 | above, the bus master under test should detect this condition and try a bus |
| 64 | recovery. This time, however, it should succeed and the device should release |
Wolfram Sang | 16d55da | 2018-06-29 11:12:46 +0200 | [diff] [blame] | 65 | SDA after toggling SCL. |
| 66 | |
Wolfram Sang | bbe8997 | 2018-06-29 11:12:47 +0200 | [diff] [blame] | 67 | "incomplete_write_byte" |
| 68 | ----------------------- |
| 69 | |
| 70 | Similar to above, this file is write only and you need to write the address of |
| 71 | an existing I2C client device to it. |
| 72 | |
| 73 | The injector will again stop at one ACK phase, so the device will keep SDA low |
| 74 | because it acknowledges data. However, there are two differences compared to |
| 75 | 'incomplete_address_phase': |
| 76 | |
| 77 | a) the message sent out will be a write message |
| 78 | b) after the address byte, a 0x00 byte will be transferred. Then, stop at ACK. |
| 79 | |
| 80 | This is a highly delicate state, the device is set up to write any data to |
| 81 | register 0x00 (if it has registers) when further clock pulses happen on SCL. |
| 82 | This is why bus recovery (up to 9 clock pulses) must either check SDA or send |
| 83 | additional STOP conditions to ensure the bus has been released. Otherwise |
| 84 | random data will be written to a device! |
| 85 | |
Wolfram Sang | 63e57b6 | 2019-02-19 17:39:45 +0100 | [diff] [blame] | 86 | Lost arbitration |
| 87 | ================ |
| 88 | |
| 89 | Here, we want to simulate the condition where the master under test loses the |
| 90 | bus arbitration against another master in a multi-master setup. |
| 91 | |
| 92 | "lose_arbitration" |
| 93 | ------------------ |
| 94 | |
| 95 | This file is write only and you need to write the duration of the arbitration |
| 96 | intereference (in µs, maximum is 100ms). The calling process will then sleep |
| 97 | and wait for the next bus clock. The process is interruptible, though. |
| 98 | |
| 99 | Arbitration lost is achieved by waiting for SCL going down by the master under |
| 100 | test and then pulling SDA low for some time. So, the I2C address sent out |
| 101 | should be corrupted and that should be detected properly. That means that the |
| 102 | address sent out should have a lot of '1' bits to be able to detect corruption. |
| 103 | There doesn't need to be a device at this address because arbitration lost |
| 104 | should be detected beforehand. Also note, that SCL going down is monitored |
| 105 | using interrupts, so the interrupt latency might cause the first bits to be not |
| 106 | corrupted. A good starting point for using this fault injector on an otherwise |
Mauro Carvalho Chehab | ccf988b | 2019-07-26 09:51:16 -0300 | [diff] [blame] | 107 | idle bus is:: |
Wolfram Sang | 63e57b6 | 2019-02-19 17:39:45 +0100 | [diff] [blame] | 108 | |
Mauro Carvalho Chehab | ccf988b | 2019-07-26 09:51:16 -0300 | [diff] [blame] | 109 | # echo 200 > lose_arbitration & |
| 110 | # i2cget -y <bus_to_test> 0x3f |
Wolfram Sang | bb6bdd5 | 2019-02-19 17:39:46 +0100 | [diff] [blame] | 111 | |
| 112 | Panic during transfer |
| 113 | ===================== |
| 114 | |
| 115 | This fault injector will create a Kernel panic once the master under test |
| 116 | started a transfer. This usually means that the state machine of the bus master |
| 117 | driver will be ungracefully interrupted and the bus may end up in an unusual |
| 118 | state. Use this to check if your shutdown/reboot/boot code can handle this |
| 119 | scenario. |
| 120 | |
| 121 | "inject_panic" |
| 122 | -------------- |
| 123 | |
| 124 | This file is write only and you need to write the delay between the detected |
| 125 | start of a transmission and the induced Kernel panic (in µs, maximum is 100ms). |
| 126 | The calling process will then sleep and wait for the next bus clock. The |
| 127 | process is interruptible, though. |
| 128 | |
| 129 | Start of a transfer is detected by waiting for SCL going down by the master |
Mauro Carvalho Chehab | ccf988b | 2019-07-26 09:51:16 -0300 | [diff] [blame] | 130 | under test. A good starting point for using this fault injector is:: |
Wolfram Sang | bb6bdd5 | 2019-02-19 17:39:46 +0100 | [diff] [blame] | 131 | |
Mauro Carvalho Chehab | ccf988b | 2019-07-26 09:51:16 -0300 | [diff] [blame] | 132 | # echo 0 > inject_panic & |
| 133 | # i2cget -y <bus_to_test> <some_address> |
Wolfram Sang | bb6bdd5 | 2019-02-19 17:39:46 +0100 | [diff] [blame] | 134 | |
| 135 | Note that there doesn't need to be a device listening to the address you are |
| 136 | using. Results may vary depending on that, though. |