summaryrefslogtreecommitdiff
path: root/common/host_event_commands.c
diff options
context:
space:
mode:
authorFurquan Shaikh <furquan@chromium.org>2017-10-13 13:08:34 -0700
committerchrome-bot <chrome-bot@chromium.org>2017-10-18 23:14:18 -0700
commit5bd5f1b1fa005dbe1cc3c763919270e01a38b8d2 (patch)
tree4190173e20f8a457c79cf67ba356707dfae44ed0 /common/host_event_commands.c
parent05d59d14c9d89a567bbdaede79f8b1d81e5e7c42 (diff)
downloadchrome-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.c131
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");
/*****************************************************************************/