Commit 7aaa0aa
stm32xx-i2c: fix notification-induced crash
The I2C code uses the kernel timer to attempt to detect cases where the
hardware has "gone away" and stopped generating interrupts.
(What this _actually_ means is that the software state machine has
gotten a transition wrong: we've never found evidence of misbehavior in
the hardware block, at least so far. I'm including this caveat for
people who find this commit online later.)
However, this code has contained two bugs, either of which could crash
the driver.
First, the race condition. Under high load (say, when a crash dump is
being recorded), the I2C driver may not reliably clear accumulated
timer-expired notifications. This can happen as follows:
1. The hardware interrupt arrives. The kernel maps it to the I2C
driver's notification mask. The notification bit is immediately set,
and the driver is returned to "runnable" state.
2. Load continues and the driver does not actually get to run.
3. The driver's timer goes off. The kernel sets the timer notification
bit. However, because the driver has already technically been woken
up with an atomic snapshot of notification conditions, the bit will
not be _observed_ until the next recv in the driver task.
4. Next time the driver wants to impose a timeout, it sets up the timer
and listens for timer notifications. It receives one immediately,
decides it has "lost an interrupt," and crashes itself.
Second, and hopefully less likely, this behavior allows the driver to be
killed by any other task using `sys_post` to the driver's timer bit.
This is because the I2C driver assumes that any timer notification that
happens before a hardware operation complete implies a failure. This is
obviously not true if the timer notification is made up.
The root cause for both of these is that the I2C driver's time
management code was not following best practices for Hubris timers and
interrupts, which is to _verify that the condition has actually
occurred_ before responding to a notification bit. This prevents
notifications "hung over" from a previous run from disturbing the next
run, and blocks other tasks from disrupting execution as a side effect.
This commit fixes that, by inserting a timer check loop around the recv.1 parent 73220f0 commit 7aaa0aa
1 file changed
Lines changed: 28 additions & 13 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1196 | 1196 | | |
1197 | 1197 | | |
1198 | 1198 | | |
1199 | | - | |
1200 | | - | |
1201 | | - | |
1202 | | - | |
1203 | | - | |
1204 | | - | |
1205 | | - | |
1206 | | - | |
1207 | | - | |
1208 | | - | |
1209 | | - | |
1210 | | - | |
1211 | | - | |
| 1199 | + | |
| 1200 | + | |
| 1201 | + | |
| 1202 | + | |
| 1203 | + | |
| 1204 | + | |
| 1205 | + | |
| 1206 | + | |
| 1207 | + | |
| 1208 | + | |
| 1209 | + | |
| 1210 | + | |
| 1211 | + | |
| 1212 | + | |
| 1213 | + | |
| 1214 | + | |
| 1215 | + | |
| 1216 | + | |
| 1217 | + | |
| 1218 | + | |
| 1219 | + | |
| 1220 | + | |
| 1221 | + | |
| 1222 | + | |
| 1223 | + | |
| 1224 | + | |
| 1225 | + | |
| 1226 | + | |
1212 | 1227 | | |
1213 | 1228 | | |
0 commit comments