summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCaveh Jalali <caveh@google.com>2017-06-20 20:13:47 -0700
committerchrome-bot <chrome-bot@chromium.org>2017-06-30 16:02:50 -0700
commit4a8b509020ce5104abf9b43335283cb39c7b75b2 (patch)
treec92a7ea90d4f60cb80ddfee78e06b8fb85f52fdd
parentbbb759ceaa843f548f90c35d1668e17c8879bad3 (diff)
downloadchrome-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.c4
-rw-r--r--common/usb_pd_protocol.c11
-rw-r--r--include/usb_pd.h9
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 */