From 53b66a0d177a1e4ebc601377e54f726c8a6896ef Mon Sep 17 00:00:00 2001 From: Yunzhi Li Date: Tue, 11 Aug 2015 17:58:14 +0800 Subject: [PATCH] libpayload: usb: dwc2: fix usb plug/unplug bug Check device connect status while waiting for usb transfer complete Avoid coreboot get stuck when usb device unplugged BUG=chrome-os-partner:35525 TEST=None BRANCH=None Change-Id: Id103501aa0d8b31b0b81bef773679c0fad79f689 Signed-off-by: Yunzhi Li Reviewed-on: https://chromium-review.googlesource.com/292630 Reviewed-by: Patrick Georgi Reviewed-by: Julius Werner Commit-Queue: Lin Huang Tested-by: Lin Huang (cherry picked from commit 2870609ceb56ccf81cda24f4cc2e10013f19adf7) Reviewed-on: https://chromium-review.googlesource.com/293300 Commit-Queue: David Hendricks Tested-by: David Hendricks --- payloads/libpayload/drivers/usb/dwc2.c | 17 ++++++++++++++++- payloads/libpayload/drivers/usb/dwc2_private.h | 1 + 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/payloads/libpayload/drivers/usb/dwc2.c b/payloads/libpayload/drivers/usb/dwc2.c index dbd7144363..49f171b9ab 100644 --- a/payloads/libpayload/drivers/usb/dwc2.c +++ b/payloads/libpayload/drivers/usb/dwc2.c @@ -140,6 +140,16 @@ static void dwc2_shutdown(hci_t *controller) free(controller); } +/* Test root port device connect status */ +static int dwc2_disconnected(hci_t *controller) +{ + dwc2_reg_t *reg = DWC2_REG(controller); + hprt_t hprt; + + hprt.d32 = readl(®->host.hprt); + return !(hprt.prtena && hprt.prtconnsts); +} + /* * This function return the actual transfer length when the transfer successe * and if the transfer fail return an error code @@ -179,8 +189,10 @@ wait_for_complete(endpoint_t *ep, uint32_t ch_num) else return -HCSTAT_UNKNOW; } - } while (timeout--); + if (dwc2_disconnected(ep->dev->controller)) + return -HCSTAT_DISCONNECTED; + } while (timeout--); /* Release the channel when hit timeout condition */ hcchar.d32 = readl(®->host.hchn[ch_num].hccharn); if (hcchar.chen) { @@ -309,6 +321,9 @@ dwc2_split_transfer(endpoint_t *ep, int size, int pid, ep_dir_t dir, /* Wait for next frame boundary */ do { hfnum.d32 = readl(®->host.hfnum); + + if (dwc2_disconnected(ep->dev->controller)) + return -HCSTAT_DISCONNECTED; } while (hfnum.frnum % 8 != 0); /* Handle Start-Split */ diff --git a/payloads/libpayload/drivers/usb/dwc2_private.h b/payloads/libpayload/drivers/usb/dwc2_private.h index 695f0b3b81..381d244f11 100644 --- a/payloads/libpayload/drivers/usb/dwc2_private.h +++ b/payloads/libpayload/drivers/usb/dwc2_private.h @@ -709,5 +709,6 @@ typedef enum { HCSTAT_NYET, HCSTAT_UNKNOW, HCSTAT_TIMEOUT, + HCSTAT_DISCONNECTED, } hcstat_t; #endif