diff options
author | Gwendal Grignou <gwendal@chromium.org> | 2017-05-22 21:31:57 -0700 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2017-06-02 18:39:37 -0700 |
commit | 92ea78398bb76fa56d3ae522d52788db6bceb2b9 (patch) | |
tree | c8e026c6eeb106e7eaa533d80114011995a9c667 | |
parent | 9ca4586129844b86ca4b346860ab658754228d2b (diff) | |
download | chrome-ec-92ea78398bb76fa56d3ae522d52788db6bceb2b9.tar.gz |
common: Add deferred erase support
Some device has large pages that take up to 2s to erase.
Add support to send a deferred erase command, that willi
be processed on HOOK task.
It can leave the other tasks (HOST_CMD) responsive.
If the whole EC can stall on flash erase, like the STM32F4 do,
at least the command FLASH_ERASE_GET_RESULT can be retried when it times
out.
BRANCH=none
TEST=Check with flashrom doing a loop of overwrites.
BUG=b:38018926
Change-Id: I8ce8e901172843d00aac0d8d59a84cbd13f58a10
Signed-off-by: Gwendal Grignou <gwendal@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/510012
Reviewed-by: Alexandru M Stan <amstan@chromium.org>
-rw-r--r-- | common/flash.c | 79 | ||||
-rw-r--r-- | include/config.h | 2 | ||||
-rw-r--r-- | include/ec_commands.h | 36 |
3 files changed, 107 insertions, 10 deletions
diff --git a/common/flash.c b/common/flash.c index 3ce7b79496..8a87cce9f3 100644 --- a/common/flash.c +++ b/common/flash.c @@ -9,6 +9,7 @@ #include "console.h" #include "flash.h" #include "gpio.h" +#include "hooks.h" #include "host_command.h" #include "shared_mem.h" #include "system.h" @@ -774,6 +775,21 @@ int flash_set_protect(uint32_t mask, uint32_t flags) return retval; } +#ifdef CONFIG_FLASH_DEFERRED_ERASE +static volatile enum ec_status erase_rc = EC_RES_SUCCESS; +static struct ec_params_flash_erase_v1 erase_info; + +static void flash_erase_deferred(void) +{ + erase_rc = EC_RES_BUSY; + if (flash_erase(erase_info.params.offset, erase_info.params.size)) + erase_rc = EC_RES_ERROR; + else + erase_rc = EC_RES_SUCCESS; +} +DECLARE_DEFERRED(flash_erase_deferred); +#endif + /*****************************************************************************/ /* Console commands */ @@ -1159,17 +1175,29 @@ DECLARE_HOST_COMMAND(EC_CMD_FLASH_WRITE, flash_command_write, EC_VER_MASK(0) | EC_VER_MASK(EC_VER_FLASH_WRITE)); +#ifndef CONFIG_FLASH_MULTIPLE_REGION /* * Make sure our image sizes are a multiple of flash block erase size so that * the host can erase the entire image. */ BUILD_ASSERT(CONFIG_RO_SIZE % CONFIG_FLASH_ERASE_SIZE == 0); BUILD_ASSERT(CONFIG_RW_SIZE % CONFIG_FLASH_ERASE_SIZE == 0); +#endif static int flash_command_erase(struct host_cmd_handler_args *args) { const struct ec_params_flash_erase *p = args->params; - uint32_t offset = p->offset + EC_FLASH_REGION_START; + int rc = EC_RES_SUCCESS, cmd = FLASH_ERASE_SECTOR; + uint32_t offset; +#ifdef CONFIG_FLASH_DEFERRED_ERASE + const struct ec_params_flash_erase_v1 *p_1 = args->params; + + if (args->version > 0) { + cmd = p_1->cmd; + p = &p_1->params; + } +#endif + offset = p->offset + EC_FLASH_REGION_START; if (flash_get_protect() & EC_FLASH_PROTECT_ALL_NOW) return EC_RES_ACCESS_DENIED; @@ -1177,19 +1205,50 @@ static int flash_command_erase(struct host_cmd_handler_args *args) if (system_unsafe_to_overwrite(offset, p->size)) return EC_RES_ACCESS_DENIED; - /* Indicate that we might be a while */ + switch (cmd) { + case FLASH_ERASE_SECTOR: #if defined(HAS_TASK_HOSTCMD) && defined(CONFIG_HOST_COMMAND_STATUS) - args->result = EC_RES_IN_PROGRESS; - host_send_response(args); + args->result = EC_RES_IN_PROGRESS; + host_send_response(args); #endif - if (flash_erase(offset, p->size)) - return EC_RES_ERROR; + if (flash_erase(offset, p->size)) + return EC_RES_ERROR; - return EC_RES_SUCCESS; + break; +#ifdef CONFIG_FLASH_DEFERRED_ERASE + case FLASH_ERASE_SECTOR_ASYNC: + rc = erase_rc; + if (rc == EC_RES_SUCCESS) { + memcpy(&erase_info, p_1, sizeof(*p_1)); + hook_call_deferred(&flash_erase_deferred_data, 0); + } else { + /* + * Not our job to return the result of + * the previous command. + */ + rc = EC_RES_BUSY; + } + break; + case FLASH_ERASE_GET_RESULT: + rc = erase_rc; + if (rc != EC_RES_BUSY) + /* Ready for another command */ + erase_rc = EC_RES_SUCCESS; + break; +#endif + default: + rc = EC_RES_INVALID_PARAM; + } + return rc; } -DECLARE_HOST_COMMAND(EC_CMD_FLASH_ERASE, - flash_command_erase, - EC_VER_MASK(0)); + + +DECLARE_HOST_COMMAND(EC_CMD_FLASH_ERASE, flash_command_erase, + EC_VER_MASK(0) +#ifdef CONFIG_FLASH_DEFERRED_ERASE + | EC_VER_MASK(1) +#endif + ); static int flash_command_protect(struct host_cmd_handler_args *args) { diff --git a/include/config.h b/include/config.h index 8ecf705054..d181ed79a8 100644 --- a/include/config.h +++ b/include/config.h @@ -986,6 +986,8 @@ #undef CONFIG_FLASH_ERASED_VALUE32 #undef CONFIG_FLASH_ERASE_SIZE #undef CONFIG_FLASH_ROW_SIZE +/* Allow deferred (async) flash erase */ +#undef CONFIG_FLASH_DEFERRED_ERASE /* Base address of program memory */ #undef CONFIG_PROGRAM_MEMORY_BASE diff --git a/include/ec_commands.h b/include/ec_commands.h index 998d5a1624..67e2f0926d 100644 --- a/include/ec_commands.h +++ b/include/ec_commands.h @@ -1222,11 +1222,47 @@ struct __ec_align4 ec_params_flash_write { /* Erase flash */ #define EC_CMD_FLASH_ERASE 0x0013 +/* v0 */ struct __ec_align4 ec_params_flash_erase { uint32_t offset; /* Byte offset to erase */ uint32_t size; /* Size to erase in bytes */ }; + +#define EC_VER_FLASH_WRITE 1 +/* v1 add async erase: + * subcommands can returns: + * EC_RES_SUCCESS : erased (see ERASE_SECTOR_ASYNC case below). + * EC_RES_INVALID_PARAM : offset/size are not aligned on a erase boundary. + * EC_RES_ERROR : other errors. + * EC_RES_BUSY : an existing erase operation is in progress. + * EC_RES_ACCESS_DENIED: Trying to erase running image. + * + * When ERASE_SECTOR_ASYNC returns EC_RES_SUCCESS, the operation is just + * properly queued. The user must call ERASE_GET_RESULT subcommand to get + * the proper result. + * When ERASE_GET_RESULT returns EC_RES_BUSY, the caller must wait and send + * ERASE_GET_RESULT again to get the result of ERASE_SECTOR_ASYNC. + * ERASE_GET_RESULT command may timeout on EC where flash access is not + * permitted while erasing. (For instance, STM32F4). + */ +enum ec_flash_erase_cmd { + FLASH_ERASE_SECTOR, /* Erase and wait for result */ + FLASH_ERASE_SECTOR_ASYNC, /* Erase and return immediately. */ + FLASH_ERASE_GET_RESULT, /* Ask for last erase result */ +}; + +struct __ec_align4 ec_params_flash_erase_v1 { + /* One of ec_flash_erase_cmd. */ + uint8_t cmd; + /* Pad byte; currently always contains 0 */ + uint8_t reserved; + /* No flags defined yet; set to 0 */ + uint16_t flag; + /* Same as v0 parameters. */ + struct ec_params_flash_erase params; +}; + /* * Get/set flash protection. * |