diff options
author | Diana Z <dzigterman@chromium.org> | 2020-04-30 10:07:25 -0600 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2020-05-01 22:21:44 +0000 |
commit | 5517aa585a2b0a6529cd1e2d5506dfe41d794343 (patch) | |
tree | f7f36ccd8eab966e5a671d7b67806b40ec7e5471 | |
parent | e71c333908978fdbce67441060aa7467b83b2bc3 (diff) | |
download | chrome-ec-5517aa585a2b0a6529cd1e2d5506dfe41d794343.tar.gz |
TCPMv2: Port over interrupt storm tracker from v1
Moves the storm tracker from v1 into the v2 interrupt task, to protect
against poorly behaving TCPCs crashing the EC. Also lowered threshold
to 400, based on empirical testing on waddledee with a single
interrupt storming TCPC on the system.
BRANCH=None
BUG=b:153989733
TEST=on waddledee, plugging a charger into C1 results in the port
periodically disabling instead of watchdog boot loops
Signed-off-by: Diana Z <dzigterman@chromium.org>
Change-Id: I807b411d755de3232b3b4a953cd631a34d8d9223
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2174751
Reviewed-by: Jett Rink <jettrink@chromium.org>
-rw-r--r-- | common/usbc/usbc_task.c | 42 |
1 files changed, 41 insertions, 1 deletions
diff --git a/common/usbc/usbc_task.c b/common/usbc/usbc_task.c index 3ba7a81642..8f9ab0445e 100644 --- a/common/usbc/usbc_task.c +++ b/common/usbc/usbc_task.c @@ -34,6 +34,9 @@ #define USBC_EVENT_TIMEOUT (5 * MSEC) +#define CPRINTF(format, args...) cprintf(CC_USBPD, format, ## args) +#define CPRINTS(format, args...) cprints(CC_USBPD, format, ## args) + static uint8_t paused[CONFIG_USB_PD_PORT_MAX_COUNT]; int tc_restart_tcpc(int port) @@ -76,6 +79,14 @@ void schedule_deferred_pd_interrupt(const int port) } /* + * Theoretically, we may need to support up to 400 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 400 +#define ALERT_STORM_INTERVAL SECOND + +/* * Main task entry point that handles PD interrupts for a single port * * @param p The PD port number for which to handle interrupts (pointer is @@ -85,6 +96,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; + timestamp_t time; + } storm_tracker[CONFIG_USB_PD_PORT_MAX_COUNT] = {}; ASSERT(port >= 0 && port < CONFIG_USB_PD_PORT_MAX_COUNT); @@ -106,8 +121,33 @@ 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)) { + timestamp_t now; + tcpc_alert(port); + + now = get_time(); + if (timestamp_expired(storm_tracker[port].time, + &now)) { + /* Reset timer into future */ + storm_tracker[port].time.val = + now.val + ALERT_STORM_INTERVAL; + + /* + * Start at 1 since we are processing an + * interrupt right now + */ + storm_tracker[port].count = 1; + } else if (++storm_tracker[port].count > + ALERT_STORM_MAX_COUNT) { + CPRINTS("C%d: Interrupt storm detected." + " Disabling port temporarily", + port); + + pd_set_suspend(port, 1); + pd_deferred_resume(port); + } + } } } } |