summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDiana Z <dzigterman@chromium.org>2019-05-15 11:51:17 -0600
committerchrome-bot <chrome-bot@chromium.org>2019-05-17 18:38:19 -0700
commit0ce5be61be0cedfd737535f3ca97764bc1d946b2 (patch)
treecf3ddf449919c510bf310bc1c024e932b7b136aa
parent83ea11a4fa470c1de5130d8fd5bfbacf9805278e (diff)
downloadchrome-ec-0ce5be61be0cedfd737535f3ca97764bc1d946b2.tar.gz
USB PD: Don't attempt to exit mode on a suspended port
Since suspended ports run a very tight while loop which does not include the pd_task's event processing, sysjumping an unlocked system with a suspended port hangs forever. A suspended port cannot be in an alternate mode, so this change skips setting PD_EVENT_SYSJUMP for such ports (which, currently, is only used to trigger the exit mode sequence). In the unlikely event that processing a PD interrupt causes the port to suspend after this check and before PD_EVENT_SYSJUMP is set, the sysjump loop will also send the reply event to the caller. BUG=b:131855159 BRANCH=None TEST=set a phaser port to fail TCPC initialization, verified that "sysjump RW" can still succeed with suspended port Change-Id: I948dd419718d0eb2e5ade58970ed36a8bd51b272 Signed-off-by: Diana Z <dzigterman@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/1613640 Reviewed-by: Jett Rink <jettrink@chromium.org> Reviewed-by: Paul Fagerburg <pfagerburg@chromium.org> Reviewed-by: Tim Wawrzynczak <twawrzynczak@chromium.org> Reviewed-by: Furquan Shaikh <furquan@chromium.org>
-rw-r--r--common/usb_pd_protocol.c40
1 files changed, 29 insertions, 11 deletions
diff --git a/common/usb_pd_protocol.c b/common/usb_pd_protocol.c
index 92aecfce9f..efa196925e 100644
--- a/common/usb_pd_protocol.c
+++ b/common/usb_pd_protocol.c
@@ -2221,6 +2221,19 @@ static void exit_dp_mode(int port)
}
#endif /* CONFIG_POWER_COMMON */
+#ifdef CONFIG_USB_PD_ALT_MODE_DFP
+static void notify_sysjump_ready(void)
+{
+ /*
+ * If event was set from pd_prepare_sysjump, wake the
+ * task waiting on us to complete.
+ */
+ if (sysjump_task_waiting != TASK_ID_INVALID)
+ task_set_event(sysjump_task_waiting,
+ TASK_EVENT_SYSJUMP_READY, 0);
+}
+#endif
+
#ifdef CONFIG_POWER_COMMON
static void handle_new_power_state(int port)
{
@@ -2899,13 +2912,8 @@ void pd_task(void *u)
#if defined(CONFIG_USB_PD_ALT_MODE_DFP)
if (evt & PD_EVENT_SYSJUMP) {
exit_dp_mode(port);
- /*
- * If event was set from pd_prepare_sysjump, wake the
- * task waiting on us to complete.
- */
- if (sysjump_task_waiting != TASK_ID_INVALID)
- task_set_event(sysjump_task_waiting,
- TASK_EVENT_SYSJUMP_READY, 0);
+ notify_sysjump_ready();
+
}
#endif
@@ -3617,8 +3625,17 @@ void pd_task(void *u)
tcpm_clear_pending_messages(port);
/* Wait for resume */
- while (pd[port].task_state == PD_STATE_SUSPENDED)
+ while (pd[port].task_state == PD_STATE_SUSPENDED) {
+#ifdef CONFIG_USB_PD_ALT_MODE_DFP
+ int evt = task_wait_event(-1);
+
+ if (evt & PD_EVENT_SYSJUMP)
+ /* Nothing to do for sysjump prep */
+ notify_sysjump_ready();
+#else
task_wait_event(-1);
+#endif
+ }
#ifdef CONFIG_USB_PD_TCPC
pd_hw_init(port, PD_ROLE_DEFAULT(port));
CPRINTS("TCPC p%d resumed!", port);
@@ -4466,10 +4483,11 @@ void pd_prepare_sysjump(void)
/* Exit modes before sysjump so we can cleanly enter again later */
for (i = 0; i < CONFIG_USB_PD_PORT_COUNT; i++) {
/*
- * We can't be in an alternate mode if PD comm is disabled, so
- * no need to send the event
+ * We can't be in an alternate mode if PD comm is disabled or
+ * the port is suspended, so no need to send the event
*/
- if (!pd_comm_is_enabled(i))
+ if (!pd_comm_is_enabled(i) ||
+ pd[i].task_state == PD_STATE_SUSPENDED)
continue;
sysjump_task_waiting = task_get_current();