diff options
author | Nicolas Boichat <drinkcat@chromium.org> | 2018-01-17 09:29:21 +0800 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2018-01-18 10:11:49 -0800 |
commit | 9ef3e91bdd12f3cac92cd4204bbb81f1e86f2445 (patch) | |
tree | 176537fe18151a43100c110b5c045335cd92d314 | |
parent | 0270e9db62247c4b64d07c482b81cfb1fde3b2a2 (diff) | |
download | chrome-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.c | 29 |
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. |