diff options
author | Charlie Mooney <charliemooney@chromium.org> | 2012-08-15 08:37:58 -0700 |
---|---|---|
committer | Gerrit <chrome-bot@google.com> | 2012-08-16 10:58:20 -0700 |
commit | cd55d3afaf5317eeec099338b7e79f5a1c78aa84 (patch) | |
tree | ae3b3e12da2d56ac63e18a356052404021dbcebf | |
parent | cebbe4c0e708be36140c8c0fdce45a106f824650 (diff) | |
download | chrome-ec-cd55d3afaf5317eeec099338b7e79f5a1c78aa84.tar.gz |
Snow: Possible problems with i2c error handling
Fixing a couple problems in the error handling for i2c interrupts. The
code could fail and not notice if master_start() returned an error code
with the TASK_EVEN_WAKE bit set. Now it stores the return values
separately to prevent this.
Also, the task id's that the ISR's use to wake up the i2c task after the
transfer is complete were uninitialized. They should always be
initialized by a call to dma_enable_tc_interrupt() but just in case, now
they all get a default value in dma_init() which is called on startup in
board.c
BUG=chrome-os-partner:12405
TEST=confirm that i2c is still working in both slave and master mode by
using the battery and pmu commands from the EC console, then booting up
the machine and using the keyboard. Confirm there are no error messages
on the cpu console.
Change-Id: I49c3da0bf17d0853247a37131cac9719face7ed4
Signed-off-by: Charlie Mooney <charliemooney@chromium.org>
Reviewed-on: https://gerrit.chromium.org/gerrit/30417
Reviewed-by: Vincent Palatin <vpalatin@chromium.org>
-rw-r--r-- | chip/stm32/dma.c | 6 | ||||
-rw-r--r-- | chip/stm32/i2c.c | 20 |
2 files changed, 18 insertions, 8 deletions
diff --git a/chip/stm32/dma.c b/chip/stm32/dma.c index 9d7f72df6f..c37063a894 100644 --- a/chip/stm32/dma.c +++ b/chip/stm32/dma.c @@ -193,8 +193,14 @@ void dma_test(void) void dma_init(void) { + int i; + /* Enable DMA1, we don't support DMA2 yet */ STM32_RCC_AHBENR |= RCC_AHBENR_DMA1EN; + + /* Initialize data for interrupt handlers */ + for (i = 0; i < DMA_NUM_CHANNELS; i++) + id[i] = TASK_ID_INVALID; } int dma_wait(int channel) diff --git a/chip/stm32/i2c.c b/chip/stm32/i2c.c index f74479310c..bc3aac9eac 100644 --- a/chip/stm32/i2c.c +++ b/chip/stm32/i2c.c @@ -535,7 +535,7 @@ cr_cleanup: static int i2c_master_transmit(int port, int slave_addr, uint8_t *data, int size, int stop) { - int rv; + int rv, rv_start; struct dma_channel *chan; disable_ack(port); @@ -552,17 +552,19 @@ static int i2c_master_transmit(int port, int slave_addr, uint8_t *data, STM32_I2C_CR2(port) |= CR2_DMAEN; /* Initialise i2c communication by sending START and ADDR */ - rv = master_start(port, slave_addr); + rv_start = master_start(port, slave_addr); /* If it started, wait for the transmission complete Interrupt */ - if (!rv) + if (!rv_start) rv = task_wait_event(DMA_TRANSFER_TIMEOUT_US); dma_disable(DMAC_I2C_TX); dma_disable_tc_interrupt(DMAC_I2C_TX); STM32_I2C_CR2(port) &= ~CR2_DMAEN; - if (rv && !(rv & TASK_EVENT_WAKE)) + if (rv_start) + return rv_start; + if (!(rv & TASK_EVENT_WAKE)) return rv; rv = wait_status(port, SR1_BTF, WAIT_XMIT_BTF); @@ -580,7 +582,7 @@ static int i2c_master_transmit(int port, int slave_addr, uint8_t *data, static int i2c_master_receive(int port, int slave_addr, uint8_t *data, int size) { - int rv; + int rv, rv_start; if (data == NULL || size < 1) return EC_ERROR_INVAL; @@ -596,8 +598,8 @@ static int i2c_master_receive(int port, int slave_addr, uint8_t *data, STM32_I2C_CR2(port) |= CR2_DMAEN; STM32_I2C_CR2(port) |= CR2_LAST; - rv = master_start(port, slave_addr | 1); - if (!rv) + rv_start = master_start(port, slave_addr | 1); + if (!rv_start) rv = task_wait_event(DMA_TRANSFER_TIMEOUT_US); dma_disable(DMAC_I2C_RX); @@ -605,7 +607,9 @@ static int i2c_master_receive(int port, int slave_addr, uint8_t *data, STM32_I2C_CR2(port) &= ~CR2_DMAEN; disable_ack(port); - if (rv && !(rv & TASK_EVENT_WAKE)) + if (rv_start) + return rv_start; + if (!(rv & TASK_EVENT_WAKE)) return rv; master_stop(port); |