diff options
author | Anshul Jain <anshulj@nvidia.com> | 2013-06-20 18:49:06 -0700 |
---|---|---|
committer | Anshul Jain (SW) <anshulj@nvidia.com> | 2013-06-21 11:24:24 -0700 |
commit | b9e37740c8614acd8e65210773133a4f0029705f (patch) | |
tree | 18ea82a7922861453a2ead3ed0dfc9f96a6293d8 /drivers | |
parent | 146cfe48b97eb51e21a09dda006726c1e2fcfdf1 (diff) |
misc: issp: Add usb js recovery mechanism
This change recovery the JS uC after USB resume failure by
unloading USB, resetting uC from ISSP and then reloading USB
Bug 1306389
Change-Id: I086636d4b7b91e3a2874f584fa6efbfd2cae6014
Signed-off-by: Michael Hsu <mhsu@nvidia.com>
Signed-off-by: Anshul Jain <anshulj@nvidia.com>
Reviewed-on: http://git-master/r/240004
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/misc/issp/issp.c | 54 | ||||
-rw-r--r-- | drivers/misc/issp/issp_priv.h | 1 | ||||
-rw-r--r-- | drivers/usb/core/hub.c | 22 |
3 files changed, 69 insertions, 8 deletions
diff --git a/drivers/misc/issp/issp.c b/drivers/misc/issp/issp.c index 083a22b0c681..b1fb71d19bbd 100644 --- a/drivers/misc/issp/issp.c +++ b/drivers/misc/issp/issp.c @@ -28,6 +28,8 @@ #define DRIVER_NAME "issp" +struct issp_host *g_issp_host; + static int issp_check_fw(struct issp_host *host) { const struct ihex_binrec *rec; @@ -129,6 +131,41 @@ static int issp_need_update(struct issp_host *host, bool *update) } struct issp_host *g_issp_host; +extern void roth_usb_unload(void); +extern void roth_usb_reload(void); + +#define ISSP_RECOVERY_DELAY 10 + +struct workqueue_struct *issp_workqueue; +struct delayed_work issp_recovery_work; + +static void issp_recovery_work_func(struct delayed_work *dwork) +{ + int i; + extern void roth_usb_unload(void); + extern void roth_usb_reload(void); + + pr_info("%s\n", __func__); + + for (i = 0; i < 1; i++) { + pr_info("%s: recovery attempt #%d\n", __func__, i); + roth_usb_unload(); + issp_uc_reset(); + roth_usb_reload(); + } +} + +void issp_start_recovery_work(void) +{ + pr_info("%s\n", __func__); + if (!issp_workqueue) { + pr_err("%s: no workqueue!\n", __func__); + return; + } + queue_delayed_work(issp_workqueue, &issp_recovery_work, + msecs_to_jiffies(ISSP_RECOVERY_DELAY)); + +} static int __init issp_probe(struct platform_device *pdev) { @@ -198,6 +235,14 @@ static int __init issp_probe(struct platform_device *pdev) dev_err(dev, "Firmware update failed!\n"); } + /* create workqueue to recover from failed usb resume */ + issp_workqueue = create_workqueue("issp_recovery_wq"); + if (!issp_workqueue) { + dev_err(&pdev->dev, "can't create work queue\n"); + goto err; + } + INIT_DELAYED_WORK(&issp_recovery_work, issp_recovery_work_func); + err_id: issp_uc_run(host); gpio_direction_input(pdata->data_gpio); @@ -217,6 +262,13 @@ err: static int __exit issp_remove(struct platform_device *pdev) { g_issp_host = NULL; + + /* delete workqueue used to recover from failed usb resume */ + if (issp_workqueue) { + destroy_workqueue(issp_workqueue); + issp_workqueue = NULL; + } + return 0; } @@ -225,7 +277,7 @@ static struct platform_driver issp_driver = { .driver = { .name = DRIVER_NAME, .owner = THIS_MODULE, - } + }, }; static int __init issp_init(void) diff --git a/drivers/misc/issp/issp_priv.h b/drivers/misc/issp/issp_priv.h index daaec1bb9cd2..f1988a429db8 100644 --- a/drivers/misc/issp/issp_priv.h +++ b/drivers/misc/issp/issp_priv.h @@ -54,5 +54,6 @@ int issp_read_block(struct issp_host *host, uint8_t block_idx, uint8_t addr, void issp_fw_rewind(struct issp_host *host); void issp_fw_seek_security(struct issp_host *host); uint8_t issp_fw_get_byte(struct issp_host *host); +void issp_uc_reset(void); #endif diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index b1b0fe41e07b..082c3a553739 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -2569,12 +2569,12 @@ 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 */ +/* For testing recover issp on every usb 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(); + extern void issp_start_recovery_work(void); + dev_err(&udev->dev, "USB_QUIRK_RESET_DEVICE_ON_RESUME_FAIL - start recovery work\n"); + issp_start_recovery_work(); /* device is gone after we reset it */ status = -ENODEV; } @@ -2595,10 +2595,10 @@ static int finish_port_resume(struct usb_device *udev) 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); + extern void issp_start_recovery_work(void); dev_err(&udev->dev, "USB_QUIRK_RESET_DEVICE_ON_RESUME_FAIL\n"); - issp_uc_reset(); + issp_start_recovery_work(); /* device is gone after we reset it */ status = -ENODEV; } else { @@ -3257,11 +3257,19 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, if (hcd->driver->update_device) hcd->driver->update_device(hcd, udev); fail: - if (retval) { + if (retval && + !(udev->quirks & USB_QUIRK_RESET_DEVICE_ON_RESUME_FAIL)) { hub_port_disable(hub, port1, 0); update_devnum(udev, devnum); /* for disconnect processing */ } mutex_unlock(&usb_address0_mutex); + + if (udev->quirks & USB_QUIRK_RESET_DEVICE_ON_RESUME_FAIL) { + dev_err(&udev->dev, "Reset device-failure to recover from err\n"); + extern void issp_start_recovery_work(void); + issp_start_recovery_work(); + retval = 0; + } return retval; } |