mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2026-01-10 17:41:54 +00:00
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>
This commit is contained in:
committed by
chrome-bot
parent
9ca4586129
commit
92ea78398b
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user