diff options
author | Manu Gautam <mgautam@codeaurora.org> | 2016-08-18 09:27:35 +0530 |
---|---|---|
committer | Vijayavardhan Vennapusa <vvreddy@codeaurora.org> | 2016-12-20 11:37:37 +0530 |
commit | ccca5c248db749c7975664196c6d8ce2c3b56436 (patch) | |
tree | a74a4ce0e0b4d9fb11418ad40cfac0b415677372 /drivers/usb/dwc3/dwc3-msm.c | |
parent | 2d28ff09533427b3fc0b9651eff8c1d936f2cfb4 (diff) |
USB: dwc3-msm: Perform HW reinitialization on HC died error
USB core provides atomic notifier that can be used by platform
drivers to perform hardware reset/recovery on HC died error.
This error is fatal and requires complete hardware
re-initialization. This will remove and add hcd again.
CRs-fixed: 1048766
Change-Id: Ic889ef002717a8fa33e9b7c27fab14a8778bba89
Signed-off-by: Manu Gautam <mgautam@codeaurora.org>
Signed-off-by: Chandana Kishori Chiluveru <cchiluve@codeaurora.org>
Signed-off-by: Vijayavardhan Vennapusa <vvreddy@codeaurora.org>
Diffstat (limited to 'drivers/usb/dwc3/dwc3-msm.c')
-rw-r--r-- | drivers/usb/dwc3/dwc3-msm.c | 37 |
1 files changed, 35 insertions, 2 deletions
diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c index 15c994294c63..59850aff8164 100644 --- a/drivers/usb/dwc3/dwc3-msm.c +++ b/drivers/usb/dwc3/dwc3-msm.c @@ -204,6 +204,8 @@ struct dwc3_msm { unsigned int irq_to_affin; struct notifier_block dwc3_cpu_notifier; + struct notifier_block usbdev_nb; + bool hc_died; struct extcon_dev *extcon_vbus; struct extcon_dev *extcon_id; @@ -1484,6 +1486,33 @@ static void dwc3_restart_usb_work(struct work_struct *w) flush_delayed_work(&mdwc->sm_work); } +static int msm_dwc3_usbdev_notify(struct notifier_block *self, + unsigned long action, void *priv) +{ + struct dwc3_msm *mdwc = container_of(self, struct dwc3_msm, usbdev_nb); + struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3); + struct usb_bus *bus = priv; + + /* Interested only in recovery when HC dies */ + if (action != USB_BUS_DIED) + return 0; + + dev_dbg(mdwc->dev, "%s initiate recovery from hc_died\n", __func__); + /* Recovery already under process */ + if (mdwc->hc_died) + return 0; + + if (bus->controller != &dwc->xhci->dev) { + dev_dbg(mdwc->dev, "%s event for diff HCD\n", __func__); + return 0; + } + + mdwc->hc_died = true; + schedule_delayed_work(&mdwc->sm_work, 0); + return 0; +} + + /* * Check whether the DWC3 requires resetting the ep * after going to Low Power Mode (lpm) @@ -3154,6 +3183,8 @@ static int dwc3_otg_start_host(struct dwc3_msm *mdwc, int on) mdwc->host_nb.notifier_call = dwc3_msm_host_notifier; usb_register_notify(&mdwc->host_nb); + mdwc->usbdev_nb.notifier_call = msm_dwc3_usbdev_notify; + usb_register_atomic_notify(&mdwc->usbdev_nb); /* * FIXME If micro A cable is disconnected during system suspend, * xhci platform device will be removed before runtime pm is @@ -3197,6 +3228,7 @@ static int dwc3_otg_start_host(struct dwc3_msm *mdwc, int on) } else { dev_dbg(mdwc->dev, "%s: turn off host\n", __func__); + usb_unregister_atomic_notify(&mdwc->usbdev_nb); if (!IS_ERR(mdwc->vbus_reg)) ret = regulator_disable(mdwc->vbus_reg); if (ret) { @@ -3488,11 +3520,12 @@ static void dwc3_otg_sm_work(struct work_struct *w) break; case OTG_STATE_A_HOST: - if (test_bit(ID, &mdwc->inputs)) { - dev_dbg(mdwc->dev, "id\n"); + if (test_bit(ID, &mdwc->inputs) || mdwc->hc_died) { + dev_dbg(mdwc->dev, "id || hc_died\n"); dwc3_otg_start_host(mdwc, 0); mdwc->otg_state = OTG_STATE_B_IDLE; mdwc->vbus_retry_count = 0; + mdwc->hc_died = false; work = 1; } else { dev_dbg(mdwc->dev, "still in a_host state. Resuming root hub.\n"); |