diff options
author | Furquan Shaikh <furquan@chromium.org> | 2017-10-13 13:08:34 -0700 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2017-10-18 23:14:18 -0700 |
commit | 5bd5f1b1fa005dbe1cc3c763919270e01a38b8d2 (patch) | |
tree | 4190173e20f8a457c79cf67ba356707dfae44ed0 /common/host_event_commands.c | |
parent | 05d59d14c9d89a567bbdaede79f8b1d81e5e7c42 (diff) | |
download | chrome-ec-5bd5f1b1fa005dbe1cc3c763919270e01a38b8d2.tar.gz |
host_event_commands: Add support for always reporting masks
Add a new mask type (ALWAYS_REPORT mask) that is set by default to
certain host events that should always be reported to the host
irrespective of the state of SCI, SMI and wake masks. This mask
includes host events like critical events resulting in shutdown or
reboot, events that are consumed by BIOS, etc.
Now that ALWAYS_REPORT mask is added, this change also updates the way
EC manages set/query operations for host events:
1. During set operation, EC will check if the host event is present in
any of the 4 masks - SCI, SMI, wake and always report. If yes, then it
is set in hostevents.
2. During query operation, EC will extract the lowest set event from
hostevents, clear it and return it back to the host.
In order to reflect the above change in EC behavior, a new feature bit
is used EC_FEATURE_UNIFIED_WAKE_MASKS. This allows the host to decide
when wake mask needs to be set before checking for host events.
BUG=None
BRANCH=None
TEST=make -j buildall. Also verified following:
1. Wake from S3 works as expected. Host is able to log correct wake
sources (Verified power button, lid open, base key press and tablet
mode change on soraka).
2. Wake from S5 works as expected. Host is able to log correct wake
sources (Verified power button, lid open on soraka).
3. Wake from S0ix works as expected (Verified power button, lid open
on soraka).
4. Software method to trigger recovery still works fine:
reboot ap-off
hostevent set 0x4000
powerb
Change-Id: I62e5c1f82247c82348cd019e082883d86ec2688f
Signed-off-by: Furquan Shaikh <furquan@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/719578
Reviewed-by: Aaron Durbin <adurbin@chromium.org>
Diffstat (limited to 'common/host_event_commands.c')
-rw-r--r-- | common/host_event_commands.c | 131 |
1 files changed, 98 insertions, 33 deletions
diff --git a/common/host_event_commands.c b/common/host_event_commands.c index 714eaf42ec..d2fa584855 100644 --- a/common/host_event_commands.c +++ b/common/host_event_commands.c @@ -22,7 +22,37 @@ #ifdef CONFIG_LPC #define LPC_SYSJUMP_TAG 0x4c50 /* "LP" */ -#define LPC_SYSJUMP_VERSION 1 +#define LPC_SYSJUMP_OLD_VERSION 1 +#define LPC_SYSJUMP_VERSION 2 + +/* + * Always report mask includes mask of host events that need to be reported in + * host event always irrespective of the state of SCI, SMI and wake masks. + * + * Events that indicate critical shutdown/reboots that have occurred: + * - EC_HOST_EVENT_THERMAL_SHUTDOWN + * - EC_HOST_EVENT_BATTERY_SHUTDOWN + * - EC_HOST_EVENT_HANG_REBOOT + * - EC_HOST_EVENT_PANIC + * + * Events that are consumed by BIOS: + * - EC_HOST_EVENT_KEYBOARD_RECOVERY + * - EC_HOST_EVENT_KEYBOARD_FASTBOOT + * - EC_HOST_EVENT_KEYBOARD_RECOVERY_HW_REINIT + * + * Events that are buffered and have separate data maintained of their own: + * - EC_HOST_EVENT_MKBP + * + */ +#define LPC_HOST_EVENT_ALWAYS_REPORT_DEFAULT_MASK \ + (EC_HOST_EVENT_MASK(EC_HOST_EVENT_KEYBOARD_RECOVERY) | \ + EC_HOST_EVENT_MASK(EC_HOST_EVENT_THERMAL_SHUTDOWN) | \ + EC_HOST_EVENT_MASK(EC_HOST_EVENT_BATTERY_SHUTDOWN) | \ + EC_HOST_EVENT_MASK(EC_HOST_EVENT_HANG_REBOOT) | \ + EC_HOST_EVENT_MASK(EC_HOST_EVENT_PANIC) | \ + EC_HOST_EVENT_MASK(EC_HOST_EVENT_KEYBOARD_FASTBOOT) | \ + EC_HOST_EVENT_MASK(EC_HOST_EVENT_MKBP) | \ + EC_HOST_EVENT_MASK(EC_HOST_EVENT_KEYBOARD_RECOVERY_HW_REINIT)) static uint32_t lpc_host_events; static uint32_t lpc_host_event_mask[LPC_HOST_EVENT_COUNT]; @@ -38,6 +68,17 @@ uint32_t lpc_get_host_event_mask(enum lpc_host_event_type type) return lpc_host_event_mask[type]; } +static uint32_t lpc_get_all_host_event_masks(void) +{ + uint32_t or_mask = 0; + int i; + + for (i = 0; i < LPC_HOST_EVENT_COUNT; i++) + or_mask |= lpc_get_host_event_mask(i); + + return or_mask; +} + static void lpc_set_host_event_state(uint32_t events) { if (events == lpc_host_events) @@ -59,33 +100,11 @@ uint32_t lpc_get_host_events(void) int lpc_get_next_host_event(void) { - int evt_index = 0; - int i; - const uint32_t any_mask = lpc_get_host_event_mask(LPC_HOST_EVENT_SMI) | - lpc_get_host_event_mask(LPC_HOST_EVENT_SCI) | - lpc_get_host_event_mask(LPC_HOST_EVENT_WAKE); - - for (i = 0; i < 32; i++) { - const uint32_t e = (1 << i); - - if (lpc_host_events & e) { - host_clear_events(e); - - /* - * If host hasn't unmasked this event, drop it. We do - * this at query time rather than event generation time - * so that the host has a chance to unmask events - * before they're dropped by a query. - */ - if (!(e & any_mask)) - continue; - - evt_index = i + 1; /* Events are 1-based */ - break; - } - } + int evt_idx = __builtin_ffs(lpc_host_events); - return evt_index; + if (evt_idx) + host_clear_events(1 << (evt_idx - 1)); + return evt_idx; } static void lpc_sysjump_save_mask(void) @@ -95,24 +114,53 @@ static void lpc_sysjump_save_mask(void) } DECLARE_HOOK(HOOK_SYSJUMP, lpc_sysjump_save_mask, HOOK_PRIO_DEFAULT); -static void lpc_post_sysjump_restore_mask(void) +/* + * Restore various LPC masks if they were saved before the sysjump. + * + * Returns: + * 1 = All masks were restored + * 0 = No masks were stashed before sysjump or EC performing sysjump did not + * support always report mask. + */ +static int lpc_post_sysjump_restore_mask(void) { const uint32_t *prev_mask; int size, version; prev_mask = (const uint32_t *)system_get_jump_tag(LPC_SYSJUMP_TAG, &version, &size); - if (!prev_mask || version != LPC_SYSJUMP_VERSION || - size != sizeof(lpc_host_event_mask)) - return; + if (!prev_mask || size != sizeof(lpc_host_event_mask) || + (version != LPC_SYSJUMP_VERSION && + version != LPC_SYSJUMP_OLD_VERSION)) + return 0; memcpy(lpc_host_event_mask, prev_mask, sizeof(lpc_host_event_mask)); + + return version == LPC_SYSJUMP_VERSION; +} + +uint32_t __attribute__((weak)) lpc_override_always_report_mask(void) +{ + return LPC_HOST_EVENT_ALWAYS_REPORT_DEFAULT_MASK; } + +static void lpc_init_mask(void) +{ + /* + * First check if masks were stashed before sysjump. If no masks were + * stashed or if the EC image performing sysjump does not support always + * report mask, then set always report mask now. + */ + if (!lpc_post_sysjump_restore_mask()) + lpc_host_event_mask[LPC_HOST_EVENT_ALWAYS_REPORT] = + lpc_override_always_report_mask(); +} + /* * This hook is required to run before chip gets to initialize LPC because * update host events will need the masks to be correctly restored. */ -DECLARE_HOOK(HOOK_INIT, lpc_post_sysjump_restore_mask, HOOK_PRIO_INIT_LPC - 1); +DECLARE_HOOK(HOOK_INIT, lpc_init_mask, HOOK_PRIO_INIT_LPC - 1); #endif @@ -142,6 +190,18 @@ void host_set_events(uint32_t mask) /* ignore host events the rest of board doesn't care about */ mask &= CONFIG_HOST_EVENT_REPORT_MASK; +#ifdef CONFIG_LPC + /* + * Host only cares about the events for which the masks are set either + * in wake mask, SCI mask or SMI mask. In addition to that, there are + * certain events that need to be always reported (Please see + * LPC_HOST_EVENT_ALWAYS_REPORT_DEFAULT_MASK). Thus, when a new host + * event is being set, ensure that it is present in one of these + * masks. Else, there is no need to process that event. + */ + mask &= lpc_get_all_host_event_masks(); +#endif + /* exit now if nothing has changed */ if (!((events & mask) != mask || (events_copy_b & mask) != mask)) return; @@ -251,6 +311,9 @@ static int command_host_event(int argc, char **argv) lpc_set_host_event_mask(LPC_HOST_EVENT_SCI, i); else if (!strcasecmp(argv[1], "wake")) lpc_set_host_event_mask(LPC_HOST_EVENT_WAKE, i); + else if (!strcasecmp(argv[1], "always_report")) + lpc_set_host_event_mask(LPC_HOST_EVENT_ALWAYS_REPORT, + i); #endif else return EC_ERROR_PARAM1; @@ -266,11 +329,13 @@ static int command_host_event(int argc, char **argv) lpc_get_host_event_mask(LPC_HOST_EVENT_SCI)); ccprintf("Wake mask: 0x%08x\n", lpc_get_host_event_mask(LPC_HOST_EVENT_WAKE)); + ccprintf("Always report mask: 0x%08x\n", + lpc_get_host_event_mask(LPC_HOST_EVENT_ALWAYS_REPORT)); #endif return EC_SUCCESS; } DECLARE_CONSOLE_COMMAND(hostevent, command_host_event, - "[set | clear | clearb | smi | sci | wake] [mask]", + "[set | clear | clearb | smi | sci | wake | always_report] [mask]", "Print / set host event state"); /*****************************************************************************/ |