diff options
author | Vadim Bendebury <vbendeb@chromium.org> | 2018-01-30 14:27:59 -0800 |
---|---|---|
committer | ChromeOS Commit Bot <chromeos-commit-bot@chromium.org> | 2018-02-01 00:48:25 +0000 |
commit | 8557630d22780f8882b35ec49cf9d3ba99529015 (patch) | |
tree | a5289271318a754a1997d0003f285bb01333769c | |
parent | 4cb1d792b969bc6f46b809dbcb8ccb97a58ea10d (diff) | |
download | chrome-ec-8557630d22780f8882b35ec49cf9d3ba99529015.tar.gz |
g: protect flash operations
Flash operations in do_flash_op() involve waiting polling for the chip
to complete the operation. If a concurrent operation is started while
another operation is in progress, flash gets confused and locks up.
Let's add a mutex to ensure that flash operation runs to completion
before another operation starts.
BRANCH=cr50
BUG=b:67651754
TEST=multiple times ran firmware update while the device was coming up
and saving TPM status in NVMEM. Observed no failures.
Change-Id: I777a38f8a63cf17d60edb11cc3f916a4ea904741
Signed-off-by: Vadim Bendebury <vbendeb@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/894180
Reviewed-by: Randall Spangler <rspangler@chromium.org>
Reviewed-by: Mary Ruthven <mruthven@chromium.org>
(cherry picked from commit cdd2c95284be89c9a7e79a27c35b0e1f1773e27f)
Reviewed-on: https://chromium-review.googlesource.com/896789
-rw-r--r-- | chip/g/flash.c | 38 |
1 files changed, 32 insertions, 6 deletions
diff --git a/chip/g/flash.c b/chip/g/flash.c index 6fd262a31d..fdb962bf00 100644 --- a/chip/g/flash.c +++ b/chip/g/flash.c @@ -46,11 +46,15 @@ #include "flash_info.h" #include "registers.h" #include "shared_mem.h" +#include "task.h" #include "timer.h" #include "watchdog.h" #define CPRINTF(format, args...) cprintf(CC_EXTENSION, format, ## args) +/* Mutex to prevent concurrent accesses to flash engine. */ +static struct mutex flash_mtx; + int flash_pre_init(void) { struct g_flash_region regions[4]; @@ -283,6 +287,9 @@ static int write_batch(int byte_offset, int is_info_bank, volatile uint32_t *fsh_wr_data = GREG32_ADDR(FLASH, FSH_WR_DATA0); uint32_t val; int i; + int rv; + + mutex_lock(&flash_mtx); /* Load the write buffer. */ for (i = 0; i < words; i++) { @@ -300,7 +307,11 @@ static int write_batch(int byte_offset, int is_info_bank, fsh_wr_data++; } - return do_flash_op(OP_WRITE_BLOCK, is_info_bank, byte_offset, words); + rv = do_flash_op(OP_WRITE_BLOCK, is_info_bank, byte_offset, words); + + mutex_unlock(&flash_mtx); + + return rv; } static int flash_physical_write_internal(int byte_offset, int is_info_bank, @@ -348,12 +359,15 @@ int flash_physical_info_read_word(int byte_offset, uint32_t *dst) if (byte_offset % CONFIG_FLASH_WRITE_SIZE) return EC_ERROR_INVAL; + mutex_lock(&flash_mtx); + ret = do_flash_op(OP_READ_BLOCK, 1, byte_offset, 1); - if (ret != EC_SUCCESS) - return ret; + if (ret == EC_SUCCESS) + *dst = GREG32(FLASH, FSH_DOUT_VAL1); - *dst = GREG32(FLASH, FSH_DOUT_VAL1); - return EC_SUCCESS; + mutex_unlock(&flash_mtx); + + return ret; } /* @@ -434,11 +448,17 @@ int flash_physical_erase(int byte_offset, int num_bytes) return EC_ERROR_INVAL; while (num_bytes) { + + mutex_lock(&flash_mtx); + /* We may be asked to erase multiple banks */ ret = do_flash_op(OP_ERASE_BLOCK, 0, /* not the INFO bank */ byte_offset, num_bytes / 4); /* word count */ + + mutex_unlock(&flash_mtx); + if (ret) { CPRINTF("Failed to erase block at %x\n", byte_offset); return ret; @@ -494,7 +514,13 @@ static int command_erase_flash_info(int argc, char **argv) } } - if (do_flash_op(OP_ERASE_BLOCK, 1, 0, 512) != EC_SUCCESS) { + mutex_lock(&flash_mtx); + + rv = do_flash_op(OP_ERASE_BLOCK, 1, 0, 512); + + mutex_unlock(&flash_mtx); + + if (rv != EC_SUCCESS) { ccprintf("Failed to erase info space!\n"); goto exit; } |