mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2025-12-27 18:25:05 +00:00
Add reboot-at-shutdown flag
Also removes unused recovery request, since AP handles that internally now. BUG=chrome-os-partner:10685 TEST=manual. From root shell, ectool reboot_ec RO -> EC reboots to RO, AP stays up ectool reboot_ec A -> EC reboots to A, AP stays up ectool reboot_ec cold -> EC reboots, AP shuts down ectool reboot_ec cold at-shutdown -> (EC stores request, but doesn't reboot) shutdown -P now -> EC reboots when AP shuts down ectool reboot_ec cold at-shutdown -> (EC stores request, but doesn't reboot) ectool reboot_ec cancel -> (EC stores cancel-request) shutdown -P now -> AP shuts down, but EC doesn't reboot Signed-off-by: Randall Spangler <rspangler@chromium.org> Change-Id: I51bbf997f6b7f94fe61f06a8a1804c3cc5c319b8 Reviewed-on: https://gerrit.chromium.org/gerrit/25791 Reviewed-by: Hung-Te Lin <hungte@chromium.org> Reviewed-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
@@ -8,12 +8,12 @@
|
||||
#include "board.h"
|
||||
#include "clock.h"
|
||||
#include "console.h"
|
||||
#include "ec_commands.h"
|
||||
#include "flash.h"
|
||||
#include "gpio.h"
|
||||
#include "hooks.h"
|
||||
#include "host_command.h"
|
||||
#include "lpc.h"
|
||||
#include "ec_commands.h"
|
||||
#include "system.h"
|
||||
#include "task.h"
|
||||
#include "uart.h"
|
||||
@@ -42,8 +42,8 @@ struct jump_data {
|
||||
* be the last word in RAM regardless of how many fields are added. */
|
||||
|
||||
/* Fields from version 3 */
|
||||
uint8_t recovery_required; /* Signal recovery mode to BIOS */
|
||||
int struct_size; /* Size of struct jump_data */
|
||||
uint8_t reserved0; /* (used in proto1 to signal recovery mode) */
|
||||
int struct_size; /* Size of struct jump_data */
|
||||
|
||||
/* Fields from version 2 */
|
||||
int jump_tag_total; /* Total size of all jump tags */
|
||||
@@ -65,7 +65,7 @@ static const char * const image_names[] = {"unknown", "RO", "A", "B"};
|
||||
static enum system_reset_cause_t reset_cause = SYSTEM_RESET_UNKNOWN;
|
||||
static int jumped_to_image;
|
||||
static int disable_jump;
|
||||
|
||||
static enum ec_reboot_cmd reboot_at_shutdown;
|
||||
|
||||
int system_is_locked(void)
|
||||
{
|
||||
@@ -109,12 +109,6 @@ enum system_reset_cause_t system_get_reset_cause(void)
|
||||
}
|
||||
|
||||
|
||||
int system_get_recovery_required(void)
|
||||
{
|
||||
return jdata->recovery_required;
|
||||
}
|
||||
|
||||
|
||||
int system_jumped_to_this_image(void)
|
||||
{
|
||||
return jumped_to_image;
|
||||
@@ -256,8 +250,7 @@ const char *system_get_image_copy_string(void)
|
||||
|
||||
/* Jump to what we hope is the init address of an image. This function does
|
||||
* not return. */
|
||||
static void jump_to_image(uint32_t init_addr,
|
||||
int recovery_required)
|
||||
static void jump_to_image(uint32_t init_addr)
|
||||
{
|
||||
void (*resetvec)(void) = (void(*)(void))init_addr;
|
||||
|
||||
@@ -278,7 +271,7 @@ static void jump_to_image(uint32_t init_addr,
|
||||
interrupt_disable();
|
||||
|
||||
/* Fill in preserved data between jumps */
|
||||
jdata->recovery_required = recovery_required != 0;
|
||||
jdata->reserved0 = 0;
|
||||
jdata->magic = JUMP_DATA_MAGIC;
|
||||
jdata->version = JUMP_DATA_VERSION;
|
||||
jdata->reset_cause = reset_cause;
|
||||
@@ -328,8 +321,7 @@ static uint32_t get_size(enum system_image_copy_t copy)
|
||||
}
|
||||
|
||||
|
||||
int system_run_image_copy(enum system_image_copy_t copy,
|
||||
int recovery_required)
|
||||
int system_run_image_copy(enum system_image_copy_t copy)
|
||||
{
|
||||
uint32_t base;
|
||||
uint32_t init_addr;
|
||||
@@ -367,7 +359,7 @@ int system_run_image_copy(enum system_image_copy_t copy,
|
||||
|
||||
CPRINTF("[%T Jumping to image %s]\n", image_names[copy]);
|
||||
|
||||
jump_to_image(init_addr, recovery_required);
|
||||
jump_to_image(init_addr);
|
||||
|
||||
/* Should never get here */
|
||||
return EC_ERROR_UNKNOWN;
|
||||
@@ -480,7 +472,7 @@ int system_common_pre_init(void)
|
||||
|
||||
/* Initialize fields added after version 2 */
|
||||
if (jdata->version < 3)
|
||||
jdata->recovery_required = 0;
|
||||
jdata->reserved0 = 0;
|
||||
|
||||
/* Struct size is now the current struct size */
|
||||
jdata->struct_size = sizeof(struct jump_data);
|
||||
@@ -497,6 +489,36 @@ int system_common_pre_init(void)
|
||||
return EC_SUCCESS;
|
||||
}
|
||||
|
||||
/* Handle a pending reboot command */
|
||||
static int handle_pending_reboot(enum ec_reboot_cmd cmd)
|
||||
{
|
||||
switch (cmd) {
|
||||
case EC_REBOOT_CANCEL:
|
||||
return EC_SUCCESS;
|
||||
case EC_REBOOT_JUMP_RO:
|
||||
return system_run_image_copy(SYSTEM_IMAGE_RO);
|
||||
case EC_REBOOT_JUMP_RW_A:
|
||||
return system_run_image_copy(SYSTEM_IMAGE_RW_A);
|
||||
case EC_REBOOT_JUMP_RW_B:
|
||||
return system_run_image_copy(SYSTEM_IMAGE_RW_B);
|
||||
case EC_REBOOT_COLD:
|
||||
system_reset(1);
|
||||
/* That shouldn't return... */
|
||||
return EC_ERROR_UNKNOWN;
|
||||
default:
|
||||
return EC_ERROR_INVAL;
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Hooks */
|
||||
|
||||
static int system_common_shutdown(void)
|
||||
{
|
||||
return handle_pending_reboot(reboot_at_shutdown);
|
||||
}
|
||||
DECLARE_HOOK(HOOK_CHIPSET_SHUTDOWN, system_common_shutdown, HOOK_PRIO_DEFAULT);
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Console commands */
|
||||
|
||||
@@ -596,11 +618,11 @@ static int command_sysjump(int argc, char **argv)
|
||||
|
||||
/* Handle named images */
|
||||
if (!strcasecmp(argv[1], "RO"))
|
||||
return system_run_image_copy(SYSTEM_IMAGE_RO, 0);
|
||||
return system_run_image_copy(SYSTEM_IMAGE_RO);
|
||||
else if (!strcasecmp(argv[1], "A"))
|
||||
return system_run_image_copy(SYSTEM_IMAGE_RW_A, 0);
|
||||
return system_run_image_copy(SYSTEM_IMAGE_RW_A);
|
||||
else if (!strcasecmp(argv[1], "B"))
|
||||
return system_run_image_copy(SYSTEM_IMAGE_RW_B, 0);
|
||||
return system_run_image_copy(SYSTEM_IMAGE_RW_B);
|
||||
|
||||
/* Check for arbitrary address */
|
||||
addr = strtoi(argv[1], &e, 0);
|
||||
@@ -609,7 +631,7 @@ static int command_sysjump(int argc, char **argv)
|
||||
|
||||
ccprintf("Jumping to 0x%08x\n", addr);
|
||||
cflush();
|
||||
jump_to_image(addr, 0);
|
||||
jump_to_image(addr);
|
||||
return EC_SUCCESS;
|
||||
}
|
||||
DECLARE_CONSOLE_COMMAND(sysjump, command_sysjump,
|
||||
@@ -717,29 +739,20 @@ DECLARE_HOST_COMMAND(EC_CMD_GET_BOARD_VERSION, host_command_get_board_version);
|
||||
|
||||
int host_command_reboot(uint8_t *data, int *resp_size)
|
||||
{
|
||||
enum system_image_copy_t copy;
|
||||
struct ec_params_reboot_ec *p = (struct ec_params_reboot_ec *)data;
|
||||
int recovery_request = p->reboot_flags & EC_CMD_REBOOT_BIT_RECOVERY;
|
||||
struct ec_params_reboot_ec *p = (struct ec_params_reboot_ec *)data;
|
||||
|
||||
/* This command is only allowed on unlocked systems, because jumping
|
||||
* directly to another image bypasses verified boot. */
|
||||
if (system_is_locked())
|
||||
return EC_RES_ACCESS_DENIED;
|
||||
|
||||
switch (p->target) {
|
||||
case EC_IMAGE_RO:
|
||||
copy = SYSTEM_IMAGE_RO;
|
||||
break;
|
||||
case EC_IMAGE_RW_A:
|
||||
copy = SYSTEM_IMAGE_RW_A;
|
||||
break;
|
||||
case EC_IMAGE_RW_B:
|
||||
copy = SYSTEM_IMAGE_RW_B;
|
||||
break;
|
||||
default:
|
||||
return EC_RES_ERROR;
|
||||
if (p->cmd == EC_REBOOT_CANCEL) {
|
||||
/* Cancel pending reboot */
|
||||
reboot_at_shutdown = EC_REBOOT_CANCEL;
|
||||
return EC_RES_SUCCESS;
|
||||
} else if (p->flags & EC_REBOOT_FLAG_ON_AP_SHUTDOWN) {
|
||||
/* Store request for processing at chipset shutdown */
|
||||
reboot_at_shutdown = p->cmd;
|
||||
return EC_RES_SUCCESS;
|
||||
}
|
||||
|
||||
/* TODO: (crosbug.com/p/9040) handle EC_REBOOT_FLAG_POWER_ON */
|
||||
|
||||
#ifdef CONFIG_TASK_HOSTCMD
|
||||
#ifdef CONFIG_LPC
|
||||
/* Clean busy bits on host */
|
||||
@@ -751,14 +764,15 @@ int host_command_reboot(uint8_t *data, int *resp_size)
|
||||
#endif
|
||||
|
||||
CPUTS("[Executing host reboot command]\n");
|
||||
system_run_image_copy(copy, recovery_request);
|
||||
|
||||
/* We normally never get down here, because we'll have jumped to
|
||||
* another image. To confirm this command worked, the host will need
|
||||
* to check what image is current using GET_VERSION.
|
||||
*
|
||||
* If we DO get down here, something went wrong in the reboot, so
|
||||
* return error. */
|
||||
return EC_RES_ERROR;
|
||||
switch (handle_pending_reboot(p->cmd)) {
|
||||
case EC_SUCCESS:
|
||||
return EC_RES_SUCCESS;
|
||||
case EC_ERROR_INVAL:
|
||||
return EC_RES_INVALID_PARAM;
|
||||
case EC_ERROR_ACCESS_DENIED:
|
||||
return EC_RES_ACCESS_DENIED;
|
||||
default:
|
||||
return EC_RES_ERROR;
|
||||
}
|
||||
}
|
||||
DECLARE_HOST_COMMAND(EC_CMD_REBOOT_EC, host_command_reboot);
|
||||
|
||||
@@ -154,7 +154,7 @@ int vboot_init(void)
|
||||
switch (r) {
|
||||
case IMAGE_IS_GOOD:
|
||||
CPRINTF("[Image A verified]\n");
|
||||
system_run_image_copy(SYSTEM_IMAGE_RW_A, 0);
|
||||
system_run_image_copy(SYSTEM_IMAGE_RW_A);
|
||||
CPRINTF("[ERROR: Unable to jump to image A]\n");
|
||||
goto bad;
|
||||
case IMAGE_IS_GOOD_BUT_USE_RO_ANYWAY:
|
||||
@@ -182,7 +182,7 @@ int vboot_init(void)
|
||||
switch (r) {
|
||||
case IMAGE_IS_GOOD:
|
||||
CPRINTF("[Image B verified]\n");
|
||||
system_run_image_copy(SYSTEM_IMAGE_RW_B, 0);
|
||||
system_run_image_copy(SYSTEM_IMAGE_RW_B);
|
||||
CPRINTF("[ERROR: Unable to jump to image B]\n");
|
||||
goto bad;
|
||||
case IMAGE_IS_GOOD_BUT_USE_RO_ANYWAY:
|
||||
|
||||
@@ -599,6 +599,33 @@ struct ec_params_switch_enable_wireless {
|
||||
uint8_t enabled;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/*****************************************************************************/
|
||||
/* System commands */
|
||||
|
||||
/* TODO: this is a confusing name, since it doesn't necessarily reboot the EC.
|
||||
* Rename to "set image" or something similar. */
|
||||
#define EC_CMD_REBOOT_EC 0xd2
|
||||
|
||||
/* Command */
|
||||
enum ec_reboot_cmd {
|
||||
EC_REBOOT_CANCEL = 0, /* Cancel a pending reboot */
|
||||
EC_REBOOT_JUMP_RO, /* Jump to RO without rebooting */
|
||||
EC_REBOOT_JUMP_RW_A, /* Jump to RW-A without rebooting */
|
||||
EC_REBOOT_JUMP_RW_B, /* Jump to RW-B without rebooting */
|
||||
EC_REBOOT_COLD, /* Cold-reboot */
|
||||
};
|
||||
|
||||
/* Flags for ec_params_reboot_ec.reboot_flags */
|
||||
#define EC_REBOOT_FLAG_RESERVED0 (1 << 0) /* Was recovery request */
|
||||
#define EC_REBOOT_FLAG_ON_AP_SHUTDOWN (1 << 1)
|
||||
#define EC_REBOOT_FLAG_POWER_ON (1 << 2)
|
||||
|
||||
struct ec_params_reboot_ec {
|
||||
uint8_t cmd; /* enum ec_reboot_cmd */
|
||||
uint8_t flags; /* See EC_REBOOT_FLAG_* */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Special commands
|
||||
*
|
||||
@@ -620,14 +647,6 @@ struct ec_params_switch_enable_wireless {
|
||||
* command. */
|
||||
#define EC_CMD_REBOOT 0xd1 /* Think "die" */
|
||||
|
||||
#define EC_CMD_REBOOT_EC 0xd2
|
||||
#define EC_CMD_REBOOT_BIT_RECOVERY (1 << 0)
|
||||
|
||||
struct ec_params_reboot_ec {
|
||||
uint8_t target; /* enum ec_current_image */
|
||||
uint8_t reboot_flags;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#endif /* !__ACPI__ */
|
||||
|
||||
#endif /* __CROS_EC_COMMANDS_H */
|
||||
|
||||
@@ -45,9 +45,6 @@ int system_common_pre_init(void);
|
||||
* the cause is not known. */
|
||||
enum system_reset_cause_t system_get_reset_cause(void);
|
||||
|
||||
/* Return a Boolean indicating if BIOS should come up in recovery mode */
|
||||
int system_get_recovery_required(void);
|
||||
|
||||
/* Record the cause of the last reset. */
|
||||
void system_set_reset_cause(enum system_reset_cause_t cause);
|
||||
|
||||
@@ -97,8 +94,7 @@ int system_unsafe_to_overwrite(uint32_t offset, uint32_t size);
|
||||
const char *system_get_image_copy_string(void);
|
||||
|
||||
/* Jump to the specified image copy. */
|
||||
int system_run_image_copy(enum system_image_copy_t copy,
|
||||
int recovery_request);
|
||||
int system_run_image_copy(enum system_image_copy_t copy);
|
||||
|
||||
/* Return the version string for an image copy, or an empty string if
|
||||
* error. If copy==SYSTEM_IMAGE_UNKNOWN, returns the version for the
|
||||
|
||||
@@ -66,8 +66,8 @@ int flash_partition(enum ec_current_image part, const uint8_t *payload,
|
||||
|
||||
current = get_version();
|
||||
if (current == part) {
|
||||
rst_req.target = part == EC_IMAGE_RO ?
|
||||
EC_IMAGE_RW_A : EC_IMAGE_RO;
|
||||
rst_req.cmd = part == EC_IMAGE_RO ?
|
||||
EC_REBOOT_JUMP_RW_A : EC_REBOOT_JUMP_RO;
|
||||
ec_command(EC_CMD_REBOOT_EC, &rst_req, sizeof(rst_req),
|
||||
NULL, 0);
|
||||
/* wait EC reboot */
|
||||
|
||||
@@ -83,7 +83,7 @@ const char help_str[] =
|
||||
" Does an ACPI Query Embedded Controller command\n"
|
||||
" readtest <patternoffset> <size>\n"
|
||||
" Reads a pattern from the EC via LPC\n"
|
||||
" reboot_ec <RO|A|B>\n"
|
||||
" reboot_ec <RO|A|B> [at-shutdown]\n"
|
||||
" Reboot EC to RO or RW A/B\n"
|
||||
" sertest\n"
|
||||
" Serial output test for COM2\n"
|
||||
@@ -327,38 +327,49 @@ int cmd_read_test(int argc, char *argv[])
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int cmd_reboot_ec(int argc, char *argv[])
|
||||
{
|
||||
struct ec_params_reboot_ec p;
|
||||
int rv;
|
||||
int i;
|
||||
|
||||
if (argc < 2) {
|
||||
rv = ec_command(EC_CMD_REBOOT, NULL, 0, NULL, 0);
|
||||
} else if (argc == 2) {
|
||||
if (!strcmp(argv[1], "RO")) {
|
||||
p.target = EC_IMAGE_RO;
|
||||
} else if (!strcmp(argv[1], "A")) {
|
||||
p.target = EC_IMAGE_RW_A;
|
||||
} else if (!strcmp(argv[1], "B")) {
|
||||
p.target = EC_IMAGE_RW_B;
|
||||
} else {
|
||||
fprintf(stderr,
|
||||
"Not supported firmware copy: %s\n", argv[1]);
|
||||
return -1;
|
||||
}
|
||||
/*
|
||||
* No params specified so tell the EC to reboot immediately.
|
||||
* That reboots the AP as well, so unlikely we'll be around
|
||||
* to see a return code from this...
|
||||
*/
|
||||
return ec_command(EC_CMD_REBOOT, NULL, 0, NULL, 0);
|
||||
}
|
||||
|
||||
rv = ec_command(EC_CMD_REBOOT_EC,
|
||||
&p, sizeof(p), NULL, 0);
|
||||
} else {
|
||||
fprintf(stderr, "Wrong argument count: %d\n", argc);
|
||||
/* Parse command */
|
||||
if (!strcmp(argv[1], "cancel"))
|
||||
p.cmd = EC_REBOOT_CANCEL;
|
||||
else if (!strcmp(argv[1], "RO"))
|
||||
p.cmd = EC_REBOOT_JUMP_RO;
|
||||
else if (!strcmp(argv[1], "A"))
|
||||
p.cmd = EC_REBOOT_JUMP_RW_A;
|
||||
else if (!strcmp(argv[1], "B"))
|
||||
p.cmd = EC_REBOOT_JUMP_RW_B;
|
||||
else if (!strcmp(argv[1], "cold"))
|
||||
p.cmd = EC_REBOOT_COLD;
|
||||
else {
|
||||
fprintf(stderr, "Unknown command: %s\n", argv[1]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (rv)
|
||||
return rv;
|
||||
/* Parse flags, if any */
|
||||
p.flags = 0;
|
||||
for (i = 2; i < argc; i++) {
|
||||
if (!strcmp(argv[i], "at-shutdown"))
|
||||
p.flags |= EC_REBOOT_FLAG_ON_AP_SHUTDOWN;
|
||||
else {
|
||||
fprintf(stderr, "Unknown flag: %s\n", argv[i]);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
printf("done.\n");
|
||||
return 0;
|
||||
return ec_command(EC_CMD_REBOOT_EC, &p, sizeof(p), NULL, 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user