diff options
author | Caveh Jalali <caveh@google.com> | 2017-06-20 20:13:47 -0700 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2017-06-30 16:02:50 -0700 |
commit | 4a8b509020ce5104abf9b43335283cb39c7b75b2 (patch) | |
tree | c92a7ea90d4f60cb80ddfee78e06b8fb85f52fdd | |
parent | bbb759ceaa843f548f90c35d1668e17c8879bad3 (diff) | |
download | chrome-ec-4a8b509020ce5104abf9b43335283cb39c7b75b2.tar.gz |
usb_pd: only service interrupts on enabled ports.
as it turns out, we're pretty aggressive in iterating over all TCPCs
checking for alerts when any of them generate an interrupt or their
interrupt line is low. this can cause unfortunate behavior if the
driver hasn't initialized itself (and the chip) yet for interrupts to
be handled or we've released (disconnected) the driver so we can do a
TCPC firmware update. so, check the PD task state to see if it makes
sense to service the port's interrupt.
note: there seems to be a quirk with the ps8751 in that it holds its
ALERT# (interrupt) line low during firmware update. this line is
supposed to be falling edge triggered, so it's technically not
interrupting, but since we also poll the line level, we think there's
a continuous interrupt that isn't acutally there. we get away with
this because pd_exchange_status() has a 5ms delay in its polling loop
to avoid spinning.
the particular test case was to unplug the PD power brick during TCPC
firmware update (over i2c). the interrupt handler would be called,
accessing the TCPC over i2c and causing all sorts of havoc.
TEST=tested with follow-up CLs and verified ps8751 firmware update
works on electro.
BRANCH=none
BUG=b:35586896
Change-Id: I880cff49e0e9637256efa9003bcc46274536e631
Signed-off-by: Caveh Jalali <caveh@google.com>
Reviewed-on: https://chromium-review.googlesource.com/544661
Reviewed-by: Stefan Reinauer <reinauer@chromium.org>
Reviewed-by: Shawn N <shawnn@chromium.org>
-rw-r--r-- | common/host_command_pd.c | 4 | ||||
-rw-r--r-- | common/usb_pd_protocol.c | 11 | ||||
-rw-r--r-- | include/usb_pd.h | 9 |
3 files changed, 23 insertions, 1 deletions
diff --git a/common/host_command_pd.c b/common/host_command_pd.c index ffd2d3b996..2a60734570 100644 --- a/common/host_command_pd.c +++ b/common/host_command_pd.c @@ -16,6 +16,7 @@ #include "task.h" #include "tcpm.h" #include "timer.h" +#include "usb_pd.h" #include "usb_pd_tcpm.h" #include "util.h" @@ -139,7 +140,8 @@ static void pd_service_tcpc_ports(uint16_t port_status) int i; for (i = 0; i < CONFIG_USB_PD_PORT_COUNT; i++) { - if (port_status & (PD_STATUS_TCPC_ALERT_0 << i)) + if ((port_status & (PD_STATUS_TCPC_ALERT_0 << i)) && + pd_is_port_enabled(i)) tcpc_alert(i); } } diff --git a/common/usb_pd_protocol.c b/common/usb_pd_protocol.c index 7dbe39171a..bb09a44819 100644 --- a/common/usb_pd_protocol.c +++ b/common/usb_pd_protocol.c @@ -3166,6 +3166,17 @@ void pd_set_suspend(int port, int enable) } } +int pd_is_port_enabled(int port) +{ + switch (pd[port].task_state) { + case PD_STATE_DISABLED: + case PD_STATE_SUSPENDED: + return 0; + default: + return 1; + } +} + #if defined(CONFIG_CMD_PD) && defined(CONFIG_CMD_PD_FLASH) static int hex8tou32(char *str, uint32_t *val) { diff --git a/include/usb_pd.h b/include/usb_pd.h index 0fdf7e19fa..cefe8abe06 100644 --- a/include/usb_pd.h +++ b/include/usb_pd.h @@ -1443,6 +1443,15 @@ int pd_rx_started(int port); */ void pd_set_suspend(int port, int enable); +/** + * Check if the port has been initialized and PD task has not been + * suspended. + * + * @param port USB-C port number + * @return true if the PD task is not suspended. + */ +int pd_is_port_enabled(int port); + /* Callback when the hardware has detected an incoming packet */ void pd_rx_event(int port); /* Start sampling the CC line for reception */ |