chromeec: Read EC uptime info on boot

Additional diagnostic information about the EC and the most recent
reasons why it has reset the AP are read out and logged via printk.
This may aid in debugging spurious hangs and/or resets on the AP by
providing traceability to the EC when it triggered the reset.  Merely
knowing that the EC was also recently reset may provide valuable
intelligence.  See also https://crrev.com/c/1139028.

Change-Id: Ie6abe645d5acefb570b9f6a3c4a4b60d5bcd63cd
Signed-off-by: Jonathan Brandmeyer <jbrandmeyer@chromium.org>
Reviewed-on: https://review.coreboot.org/27621
Reviewed-by: Furquan Shaikh <furquan@google.com>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
This commit is contained in:
Jonathan Brandmeyer 2018-07-23 16:44:51 -06:00 committed by Aaron Durbin
parent 6bffc5c269
commit bd21f2844b
1 changed files with 132 additions and 4 deletions

View File

@ -892,8 +892,7 @@ int google_chromeec_set_usb_pd_role(u8 port, enum usb_pd_control_role role)
#ifndef __SMM__ #ifndef __SMM__
static static int google_chromeec_hello(void)
int google_chromeec_hello(void)
{ {
struct chromeec_command cec_cmd; struct chromeec_command cec_cmd;
struct ec_params_hello cmd_hello; struct ec_params_hello cmd_hello;
@ -912,6 +911,135 @@ int google_chromeec_hello(void)
return cec_cmd.cmd_code; return cec_cmd.cmd_code;
} }
/*
* Convert a reset cause ID to human-readable string, providing total coverage
* of the 'cause' space. The returned string points to static storage and must
* not be free()ed.
*/
static const char *reset_cause_to_str(uint16_t cause)
{
/* See also ChromiumOS EC include/chipset.h for details. */
static const char * const reset_causes[] = {
"(reset unknown)",
"reset: board custom",
"reset: ap hang detected",
"reset: console command",
"reset: keyboard sysreset",
"reset: keyboard warm reboot",
"reset: debug warm reboot",
"reset: at AP's request",
"reset: during EC initialization",
};
static const size_t shutdown_cause_begin = 1 << 15;
static const char * const shutdown_causes[] = {
"shutdown: power failure",
"shutdown: during EC initialization",
"shutdown: board custom",
"shutdown: battery voltage startup inhibit",
"shutdown: power wait asserted",
"shutdown: critical battery",
"shutdown: by console command",
"shutdown: entering G3",
"shutdown: thermal",
"shutdown: power button",
};
if (cause < ARRAY_SIZE(reset_causes))
return reset_causes[cause];
if (cause < shutdown_cause_begin)
return "(reset unknown)";
if (cause < shutdown_cause_begin + ARRAY_SIZE(shutdown_causes))
return shutdown_causes[cause - shutdown_cause_begin];
return "(shutdown unknown)";
}
/*
* Copy the EC's information about resets of the AP and its own uptime for
* debugging purposes.
*/
static void google_chromeec_log_uptimeinfo(void)
{
/* See also ChromiumOS EC include/system.h RESET_FLAG for details. */
static const char * const reset_flag_strings[] = {
"other",
"reset-pin",
"brownout",
"power-on",
"watchdog",
"soft",
"hibernate",
"rtc-alarm",
"wake-pin",
"low-battery",
"sysjump",
"hard",
"ap-off",
"preserved",
"usb-resume",
"rdd",
"rbox",
"security"
};
struct ec_response_uptime_info cmd_resp;
int i, flag, flag_count;
struct chromeec_command get_uptime_cmd = {
.cmd_code = EC_CMD_GET_UPTIME_INFO,
.cmd_version = 0,
.cmd_data_in = NULL,
.cmd_size_in = 0,
.cmd_data_out = &cmd_resp,
.cmd_size_out = sizeof(cmd_resp),
.cmd_dev_index = 0,
};
google_chromeec_command(&get_uptime_cmd);
if (get_uptime_cmd.cmd_code) {
/*
* Deliberately say nothing for EC's that don't support this
* command
*/
return;
}
printk(BIOS_DEBUG, "Google Chrome EC uptime: %d.%03d seconds\n",
cmd_resp.time_since_ec_boot_ms / MSECS_PER_SEC,
cmd_resp.time_since_ec_boot_ms % MSECS_PER_SEC);
printk(BIOS_DEBUG, "Google Chrome AP resets since EC boot: %d\n",
cmd_resp.ap_resets_since_ec_boot);
printk(BIOS_DEBUG, "Google Chrome most recent AP reset causes:\n");
for (i = 0; i != ARRAY_SIZE(cmd_resp.recent_ap_reset); ++i) {
if (cmd_resp.recent_ap_reset[i].reset_time_ms == 0)
continue;
printk(BIOS_DEBUG, "\t%d.%03d: %d %s\n",
cmd_resp.recent_ap_reset[i].reset_time_ms /
MSECS_PER_SEC,
cmd_resp.recent_ap_reset[i].reset_time_ms %
MSECS_PER_SEC,
cmd_resp.recent_ap_reset[i].reset_cause,
reset_cause_to_str(
cmd_resp.recent_ap_reset[i].reset_cause));
}
printk(BIOS_DEBUG, "Google Chrome EC reset flags at last EC boot: ");
flag_count = 0;
for (flag = 0; flag != ARRAY_SIZE(reset_flag_strings); ++flag) {
if ((cmd_resp.ec_reset_flags & (1 << flag)) != 0) {
if (flag_count)
printk(BIOS_DEBUG, " | ");
printk(BIOS_DEBUG, reset_flag_strings[flag]);
flag_count++;
}
}
printk(BIOS_DEBUG, "\n");
}
static int ec_image_type; /* Cached EC image type (ro or rw). */ static int ec_image_type; /* Cached EC image type (ro or rw). */
void google_chromeec_init(void) void google_chromeec_init(void)
@ -919,8 +1047,6 @@ void google_chromeec_init(void)
struct chromeec_command cec_cmd; struct chromeec_command cec_cmd;
struct ec_response_get_version cec_resp = {{0}}; struct ec_response_get_version cec_resp = {{0}};
printk(BIOS_DEBUG, "Google Chrome EC: Initializing keyboard.\n");
google_chromeec_hello(); google_chromeec_hello();
cec_cmd.cmd_code = EC_CMD_GET_VERSION; cec_cmd.cmd_code = EC_CMD_GET_VERSION;
@ -942,6 +1068,8 @@ void google_chromeec_init(void)
cec_resp.current_image); cec_resp.current_image);
ec_image_type = cec_resp.current_image; ec_image_type = cec_resp.current_image;
} }
google_chromeec_log_uptimeinfo();
} }
int google_ec_running_ro(void) int google_ec_running_ro(void)