From 240470a54b234704bd77f9485e06af5fc41d52d2 Mon Sep 17 00:00:00 2001 From: Vincent Palatin Date: Fri, 22 Jun 2012 23:39:59 +0000 Subject: [PATCH] stm32: fix race condition in I2C response When we are transmitting a response to the EC, we don't want to race with the TX empty interrupt handler. So just disable I2C interrupt during the transmission. Signed-off-by: Vincent Palatin BUG=None TEST=on Lucas DVT, use the keyboard and see we are no longer getting "bad checksum" in the kernel log. Change-Id: Ic59532d1ac0a3eabb67ba0d498940986282bd87f Reviewed-on: https://gerrit.chromium.org/gerrit/26162 Commit-Ready: Vincent Palatin Reviewed-by: Vincent Palatin Tested-by: Vincent Palatin --- chip/stm32/i2c.c | 45 +++++++++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/chip/stm32/i2c.c b/chip/stm32/i2c.c index a51a249fe6..1573561139 100644 --- a/chip/stm32/i2c.c +++ b/chip/stm32/i2c.c @@ -50,6 +50,26 @@ static int rx_index; /* indicates if a wait loop should abort */ static volatile int abort_transaction; +static inline void disable_i2c_interrupt(int port) +{ + STM32_I2C_CR2(port) &= ~(3 << 8); +} + +static inline void enable_i2c_interrupt(int port) +{ + STM32_I2C_CR2(port) |= 3 << 8; +} + +static inline void enable_ack(int port) +{ + STM32_I2C_CR1(port) |= (1 << 10); +} + +static inline void disable_ack(int port) +{ + STM32_I2C_CR1(port) &= ~(1 << 10); +} + static int wait_tx(int port) { static timestamp_t deadline; @@ -67,6 +87,9 @@ static int i2c_write_raw(int port, void *buf, int len) int i; uint8_t *data = buf; + /* we don't want to race with TxE interrupt event */ + disable_i2c_interrupt(port); + abort_transaction = 0; for (i = 0; i < len; i++) { STM32_I2C_DR(port) = data[i]; @@ -76,6 +99,8 @@ static int i2c_write_raw(int port, void *buf, int len) } } + enable_i2c_interrupt(port); + return len; } @@ -281,26 +306,6 @@ DECLARE_HOOK(HOOK_INIT, i2c_init, HOOK_PRIO_DEFAULT); #define SR1_PECERR (1 << 12) /* PEC err in reception */ #define SR1_TIMEOUT (1 << 14) /* Timeout : 25ms */ -static inline void disable_i2c_interrupt(int port) -{ - STM32_I2C_CR2(port) &= ~(3 << 8); -} - -static inline void enable_i2c_interrupt(int port) -{ - STM32_I2C_CR2(port) |= 3 << 8; -} - -static inline void enable_ack(int port) -{ - STM32_I2C_CR1(port) |= (1 << 10); -} - -static inline void disable_ack(int port) -{ - STM32_I2C_CR1(port) &= ~(1 << 10); -} - static inline void dump_i2c_reg(int port) { #ifdef CONFIG_DEBUG_I2C