summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVadim Bendebury <vbendeb@chromium.org>2018-01-30 14:27:59 -0800
committerChromeOS Commit Bot <chromeos-commit-bot@chromium.org>2018-02-01 00:48:25 +0000
commit8557630d22780f8882b35ec49cf9d3ba99529015 (patch)
treea5289271318a754a1997d0003f285bb01333769c
parent4cb1d792b969bc6f46b809dbcb8ccb97a58ea10d (diff)
downloadchrome-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.c38
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;
}