summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicolas Boichat <drinkcat@chromium.org>2018-01-17 09:29:21 +0800
committerchrome-bot <chrome-bot@chromium.org>2018-01-18 10:11:49 -0800
commit9ef3e91bdd12f3cac92cd4204bbb81f1e86f2445 (patch)
tree176537fe18151a43100c110b5c045335cd92d314
parent0270e9db62247c4b64d07c482b81cfb1fde3b2a2 (diff)
downloadchrome-ec-9ef3e91bdd12f3cac92cd4204bbb81f1e86f2445.tar.gz
stm32/usb: Add logic to detect stuck controller in usb_wake
When we tried to go back to sleep immediately after receiving a spurious USB resume event, the controller would get stuck in an unrecoverable state. Hopefully we fixed the resume logic, but this code would catch other cases, and recover the base. BRANCH=none BUG=b:35775088 BUG=b:67766202 BUG=b:71688150 TEST=With badly implemented resume logic (e.g. call usb_resume_deferred directly from usb_resume), with USB autosuspend enabled on soraka, short D+/D- lines. Next wake event from staff shows "USB stuck", and then USB interface recovers. Signed-off-by: Nicolas Boichat <drinkcat@chromium.org> Change-Id: I7463a37682723be195bd6a72ea5d76c21bb6cb9a Reviewed-on: https://chromium-review.googlesource.com/868094 Reviewed-by: Vincent Palatin <vpalatin@chromium.org>
-rw-r--r--chip/stm32/usb.c29
1 files changed, 28 insertions, 1 deletions
diff --git a/chip/stm32/usb.c b/chip/stm32/usb.c
index 4aec16f8d3..57e629a3d1 100644
--- a/chip/stm32/usb.c
+++ b/chip/stm32/usb.c
@@ -460,13 +460,34 @@ void board_usb_wake(void)
/* Side-band USB wake, do nothing by default. */
}
+/* Called 10ms after usb_wake started. */
+static void usb_wake_deferred(void)
+{
+ if (esof_count == 3) {
+ /*
+ * If we reach here, it means that we are not counting ESOF/SOF
+ * properly (either of these interrupts should occur every 1ms).
+ * This should never happen if we implemented the resume logic
+ * correctly.
+ *
+ * We reset the controller in that case, which recovers the
+ * interface.
+ */
+ CPRINTF("USB stuck\n");
+ STM32_RCC_APB1RSTR |= STM32_RCC_PB1_USB;
+ STM32_RCC_APB1RSTR &= ~STM32_RCC_PB1_USB;
+ usb_init();
+ }
+}
+DECLARE_DEFERRED(usb_wake_deferred);
+
void usb_wake(void)
{
if (!remote_wakeup_enabled ||
!(STM32_USB_CNTR & STM32_USB_CNTR_FSUSP)) {
/*
* USB wake not enabled, or already woken up, or already waking
- * up,nothing to do.
+ * up, nothing to do.
*/
return;
}
@@ -478,6 +499,12 @@ void usb_wake(void)
CPRINTF("WAKE\n");
/*
+ * Sometimes the USB controller gets stuck, and does not count SOF/ESOF
+ * frames anymore, detect that.
+ */
+ hook_call_deferred(&usb_wake_deferred_data, 10 * MSEC);
+
+ /*
* Set RESUME bit for 1 to 15 ms, then clear it. We ask the interrupt
* routine to count 3 ESOF interrupts, which should take between
* 2 and 3 ms.