Commit | Line | Data |
---|---|---|
05bd0728 | 1 | ========================= |
14911c6f WS |
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 | ||
05bd0728 WS |
17 | Wire states |
18 | =========== | |
19 | ||
14911c6f WS |
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 | |
05bd0728 | 41 | "incomplete transfers" class of fault injectors. |
14911c6f | 42 | |
05bd0728 WS |
43 | Incomplete transfers |
44 | ==================== | |
16d55daa WS |
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 | -------------------------- | |
14911c6f WS |
57 | |
58 | This file is write only and you need to write the address of an existing I2C | |
16d55daa WS |
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 | |
14911c6f WS |
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 | |
16d55daa WS |
65 | SDA after toggling SCL. |
66 | ||
bbe89970 WS |
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 | ||
63e57b6f WS |
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 | |
ccf988b6 | 107 | idle bus is:: |
63e57b6f | 108 | |
ccf988b6 MCC |
109 | # echo 200 > lose_arbitration & |
110 | # i2cget -y <bus_to_test> 0x3f | |
bb6bdd51 WS |
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 | |
ccf988b6 | 130 | under test. A good starting point for using this fault injector is:: |
bb6bdd51 | 131 | |
ccf988b6 MCC |
132 | # echo 0 > inject_panic & |
133 | # i2cget -y <bus_to_test> <some_address> | |
bb6bdd51 WS |
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. |