diff options
author | Randall Spangler <rspangler@chromium.org> | 2012-11-29 10:51:08 -0800 |
---|---|---|
committer | Randall Spangler <rspangler@chromium.org> | 2012-11-29 12:02:51 -0800 |
commit | 52440ef89387809af91051671a98ea9c36ce27ca (patch) | |
tree | 068f68e055c37da2d945cbe4307959e0a8d04bb5 | |
parent | 108754005d86c17b6247e83e2b7aed788d93a8c9 (diff) | |
download | chrome-ec-52440ef89387809af91051671a98ea9c36ce27ca.tar.gz |
link: Disable interrupts while reading/writing bits via onewire
When reading, the line must be sampled in a narrow timing window after
the output pulse. Interrupts or context switches during this time
corrupt the data.
Similarly, when writing, the difference between a 0-bit and a 1-bit is
the length of the output pulse. So a context switch or interrupt
there can turn a 1-bit into a 0-bit.
BUG=chrome-os-partner:15507
BRANCH=link
TEST=manual
0. plug in AC power
1. hold down shift key for the duration of this test
2. powerled yellow
3. powerled red
4. repeat steps 2-3 several times
5. release shift key
Power adapter LED should toggle color each time. (It may also toggle
to the normally expected color during this experiment, if the charging
task updates it.) Power adapter LED should NOT turn off during this test.
Change-Id: Ief11e6e9a5b07aa3a25c60c50e4e7744a4705713
Signed-off-by: Randall Spangler <rspangler@chromium.org>
Reviewed-on: https://gerrit.chromium.org/gerrit/38925
Reviewed-by: Yung-Chieh Lo <yjlou@chromium.org>
Reviewed-by: Vincent Palatin <vpalatin@chromium.org>
-rw-r--r-- | chip/lm4/onewire.c | 26 |
1 files changed, 26 insertions, 0 deletions
diff --git a/chip/lm4/onewire.c b/chip/lm4/onewire.c index 082ce1238a..0c795eeedc 100644 --- a/chip/lm4/onewire.c +++ b/chip/lm4/onewire.c @@ -9,6 +9,7 @@ #include "gpio.h" #include "hooks.h" #include "registers.h" +#include "task.h" #include "timer.h" #define ONEWIRE_PIN (1<<2) /* One-wire pin mask (on GPIO H) */ @@ -56,6 +57,12 @@ static int readbit(void) { int bit; + /* + * The delay between sending the output pulse and reading the bit is + * extremely timing sensitive, so disable interrupts. + */ + interrupt_disable(); + /* Output low */ output0(T_RL); @@ -65,6 +72,13 @@ static int readbit(void) /* Read bit */ bit = readline(); + /* + * Enable interrupt as soon as we've read the bit. The delay to the + * end of the timeslot is a lower bound, so additional latency here is + * harmless. + */ + interrupt_enable(); + /* Delay to end of timeslot */ udelay(T_SLOT - T_MSR); return bit; @@ -75,13 +89,25 @@ static int readbit(void) */ static void writebit(int bit) { + /* + * The delays in the output-low signal for sending 0 and 1 bits are + * extremely timing sensitive, so disable interrupts during that time. + * Interrupts can be enabled again as soon as the output is switched + * back to open-drain, since the delay for the rest of the timeslot is + * a lower bound. + */ if (bit) { + interrupt_disable(); output0(T_W1L); + interrupt_enable(); udelay(T_SLOT - T_W1L); } else { + interrupt_disable(); output0(T_W0L); + interrupt_enable(); udelay(T_SLOT - T_W0L); } + } int onewire_reset(void) |