summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJett Rink <jettrink@chromium.org>2019-06-07 16:18:56 -0600
committerCommit Bot <commit-bot@chromium.org>2019-08-18 03:26:54 +0000
commitb40d293f3767f196c3fc926125c467033981a02a (patch)
tree3c7a6d578420f8a93ab7ecb413b6decc5c37464b
parent538b41fc9020270737f691c20d133a2d846e720d (diff)
downloadchrome-ec-b40d293f3767f196c3fc926125c467033981a02a.tar.gz
USB PD: disable port if TCPC interrupt storm detected
If we get too many interrupts too fast, then we will starve the rest of the EC. Disable an overactive port for 5 seconds. BRANCH=none BUG=b:134702480,b:128701054 TEST=7-magic hub no longer watch dog resets phaser port 0, HDMI dongle plugged into port 1 still able to function while port 0 is periodically suspending Change-Id: Ic2d13ecc64990994ffc8e3fb68537aa909657745 Signed-off-by: Jett Rink <jettrink@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/1650484 Tested-by: Diana Z <dzigterman@chromium.org> Reviewed-by: Edward Hill <ecgh@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/1693158 Commit-Queue: Zhuohao Lee <zhuohao@chromium.org> Tested-by: Zhuohao Lee <zhuohao@chromium.org> Reviewed-by: Daisuke Nojiri <dnojiri@chromium.org>
-rw-r--r--common/usb_pd_protocol.c43
1 files changed, 41 insertions, 2 deletions
diff --git a/common/usb_pd_protocol.c b/common/usb_pd_protocol.c
index 3c72d9b0da..a75baa5c14 100644
--- a/common/usb_pd_protocol.c
+++ b/common/usb_pd_protocol.c
@@ -2557,6 +2557,14 @@ void schedule_deferred_pd_interrupt(const int port)
task_set_event(pd_int_task_id[port], PD_PROCESS_INTERRUPT, 0);
}
+/*
+ * Theoretically, we may need to support up to 480 USB-PD packets per second for
+ * intensive operations such as FW update over PD. This value has tested well
+ * preventing watchdog resets with a single bad port partner plugged in.
+ */
+#define ALERT_STORM_MAX_COUNT 480
+#define ALERT_STORM_INTERVAL SECOND
+
/**
* Main task entry point that handles PD interrupts for a single port
*
@@ -2567,6 +2575,10 @@ void pd_interrupt_handler_task(void *p)
{
const int port = (int) p;
const int port_mask = (PD_STATUS_TCPC_ALERT_0 << port);
+ struct {
+ int count;
+ uint32_t time;
+ } storm_tracker[CONFIG_USB_PD_PORT_COUNT] = { 0 };
ASSERT(port >= 0 && port < CONFIG_USB_PD_PORT_COUNT);
@@ -2588,8 +2600,30 @@ void pd_interrupt_handler_task(void *p)
* PD_PROCESS_INTERRUPT to check if we missed anything.
*/
while ((tcpc_get_alert_status() & port_mask) &&
- pd_is_port_enabled(port))
+ pd_is_port_enabled(port)) {
+ uint32_t now;
+
tcpc_alert(port);
+
+ now = get_time().le.lo;
+ if (time_after(now, storm_tracker[port].time)) {
+ storm_tracker[port].time =
+ now + ALERT_STORM_INTERVAL;
+ /*
+ * Start at 1 since we are processing
+ * an interrupt now
+ */
+ storm_tracker[port].count = 1;
+ } else if (++storm_tracker[port].count >
+ ALERT_STORM_MAX_COUNT) {
+ CPRINTS("C%d Interrupt storm detected. "
+ "Disabling port for 5 seconds.",
+ port);
+
+ pd_set_suspend(port, 1);
+ pd_deferred_resume(port);
+ }
+ }
}
}
}
@@ -3492,6 +3526,11 @@ void pd_task(void *u)
CPRINTS("TCPC p%d restart failed!", port);
break;
}
+ /* Set the CC termination and state back to default */
+ tcpm_set_cc(port,
+ PD_ROLE_DEFAULT(port) == PD_ROLE_SOURCE ?
+ TYPEC_CC_RP :
+ TYPEC_CC_RD);
set_state(port, PD_DEFAULT_STATE(port));
CPRINTS("TCPC p%d resumed!", port);
#endif
@@ -4379,7 +4418,7 @@ DECLARE_DEFERRED(resume_pd_port);
void pd_deferred_resume(int port)
{
atomic_or(&pd_ports_to_resume, 1 << port);
- hook_call_deferred(&resume_pd_port_data, SECOND);
+ hook_call_deferred(&resume_pd_port_data, 5 * SECOND);
}
#endif /* CONFIG_USB_PD_DEFERRED_RESUME */