diff options
author | Anshul Jain <anshulj@nvidia.com> | 2013-06-14 18:10:31 -0700 |
---|---|---|
committer | Mandar Padmawar <mpadmawar@nvidia.com> | 2013-06-17 02:39:53 -0700 |
commit | be97c59c55b9bf547cf0030a7dc469319bd8de94 (patch) | |
tree | 25105cd0623e19fb073fa6bd714143abdd9b73e2 | |
parent | 775f7c0f628c42e6fefd43e4990cf809d80c76c2 (diff) |
drivers:misc:issp: Reset Device on USB resume fail
This is a WAR to reset the USB device if the device
fails to resume. We assume that the resume failure is
because of the uC hang.
Signed-off-by: Anshul Jain <anshulj@nvidia.com>
Change-Id: I6fc85cd0ce2fad7a7dbff5b6ddee0a96149a5d76
Reviewed-on: http://git-master/r/239086
GVS: Gerrit_Virtual_Submit
Reviewed-by: Tao Xie <txie@nvidia.com>
Tested-by: Tao Xie <txie@nvidia.com>
Reviewed-by: Ankit Pashiney <apashiney@nvidia.com>
-rw-r--r-- | drivers/misc/issp/issp.c | 8 | ||||
-rw-r--r-- | drivers/misc/issp/issp_steps.c | 18 | ||||
-rw-r--r-- | drivers/usb/core/hub.c | 27 | ||||
-rw-r--r-- | drivers/usb/core/quirks.c | 3 | ||||
-rw-r--r-- | include/linux/usb/quirks.h | 4 |
5 files changed, 57 insertions, 3 deletions
diff --git a/drivers/misc/issp/issp.c b/drivers/misc/issp/issp.c index 05ed51684993..083a22b0c681 100644 --- a/drivers/misc/issp/issp.c +++ b/drivers/misc/issp/issp.c @@ -128,6 +128,8 @@ static int issp_need_update(struct issp_host *host, bool *update) return 0; } +struct issp_host *g_issp_host; + static int __init issp_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -162,6 +164,7 @@ static int __init issp_probe(struct platform_device *pdev) host->pdev = pdev; host->pdata = pdata; + g_issp_host = host; ret = request_ihex_firmware(&host->fw, pdata->fw_name, dev); if (ret) { dev_err(dev, "Request firmware %s failed!\n", pdata->fw_name); @@ -197,6 +200,10 @@ static int __init issp_probe(struct platform_device *pdev) err_id: issp_uc_run(host); + gpio_direction_input(pdata->data_gpio); + gpio_direction_input(pdata->clk_gpio); + release_firmware(host->fw); + return 0; err: gpio_direction_input(pdata->data_gpio); @@ -209,6 +216,7 @@ err: static int __exit issp_remove(struct platform_device *pdev) { + g_issp_host = NULL; return 0; } diff --git a/drivers/misc/issp/issp_steps.c b/drivers/misc/issp/issp_steps.c index d552e9187c29..f666b59ed7a7 100644 --- a/drivers/misc/issp/issp_steps.c +++ b/drivers/misc/issp/issp_steps.c @@ -652,6 +652,24 @@ static int issp_verify_checksum(struct issp_host *host) } /* global functions */ +extern struct issp_host *g_issp_host; + +void issp_uc_reset(void) +{ + struct issp_host *host = g_issp_host; + + if (!host) { + pr_err("%s: !host\n", __func__); + return; + } + + /* reset */ + usleep_range(ISSP_RESET_ASSERT_DELAY, ISSP_RESET_ASSERT_DELAY); + pin_reset_lo(host); + udelay(ISSP_RESET_PULSE_LENGTH); + pin_reset_hi(host); + udelay(ISSP_RESET_POST_DELAY); +} int issp_uc_program(struct issp_host *host) { diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index e727b876726c..b1b0fe41e07b 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -2569,6 +2569,17 @@ static int finish_port_resume(struct usb_device *udev) retry_reset_resume: status = usb_reset_and_verify_device(udev); +/* For testing reset on every resume */ +#if 0 + if (udev->quirks & USB_QUIRK_RESET_DEVICE_ON_RESUME_FAIL) { + extern void issp_uc_reset(void); + dev_err(&udev->dev, "USB_QUIRK_RESET_DEVICE_ON_RESUME_FAIL\n"); + issp_uc_reset(); + /* device is gone after we reset it */ + status = -ENODEV; + } +#endif + /* 10.5.4.5 says be sure devices in the tree are still there. * For now let's assume the device didn't go crazy on resume, * and device drivers will know about any resume quirks. @@ -2581,9 +2592,19 @@ static int finish_port_resume(struct usb_device *udev) /* If a normal resume failed, try doing a reset-resume */ if (status && !udev->reset_resume && udev->persist_enabled) { - dev_dbg(&udev->dev, "retry with reset-resume\n"); - udev->reset_resume = 1; - goto retry_reset_resume; + dev_err(&udev->dev, "retry with reset-resume\n"); + if (udev->quirks & + USB_QUIRK_RESET_DEVICE_ON_RESUME_FAIL) { + extern void issp_uc_reset(void); + dev_err(&udev->dev, + "USB_QUIRK_RESET_DEVICE_ON_RESUME_FAIL\n"); + issp_uc_reset(); + /* device is gone after we reset it */ + status = -ENODEV; + } else { + udev->reset_resume = 1; + goto retry_reset_resume; + } } } diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index 32d3adc315f5..ef3275bd24e5 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -28,6 +28,9 @@ * devices is broken... */ static const struct usb_device_id usb_quirk_list[] = { + /* Nvidia JS*/ + { USB_DEVICE(0x0955, 0x7203), .driver_info = USB_QUIRK_RESET_DEVICE_ON_RESUME_FAIL }, + /* CBM - Flash disk */ { USB_DEVICE(0x0204, 0x6025), .driver_info = USB_QUIRK_RESET_RESUME }, diff --git a/include/linux/usb/quirks.h b/include/linux/usb/quirks.h index 3e93de7ecbc3..9f338a69ddf1 100644 --- a/include/linux/usb/quirks.h +++ b/include/linux/usb/quirks.h @@ -30,4 +30,8 @@ descriptor */ #define USB_QUIRK_DELAY_INIT 0x00000040 +/* reset device if bus resume fails - assume that resume failure is + due to usb device crash */ +#define USB_QUIRK_RESET_DEVICE_ON_RESUME_FAIL 0x00000100 + #endif /* __LINUX_USB_QUIRKS_H */ |