On 1/10/2011 9:18 AM, Chris wrote: > Hi, > > I am using a new Logitech C910 usb webcam plugged into an OMAP3530 embedded board using Kernel 2.6.32 > > Getting this error after a period of correct operation: > [ 2890.610992] uvcvideo: Failed to query (135) UVC control 2 (unit 2) : -110 (exp. 2). > [ 2890.939117] uvcvideo: Failed to query (135) UVC control 2 (unit 2) : -110 (exp. 2). > [ 2891.267242] uvcvideo: Failed to query (135) UVC control 3 (unit 2) : -110 (exp. 2). > [ 2891.595367] uvcvideo: Failed to query (135) UVC control 7 (unit 2) : -110 (exp. 2). > [ 2891.923492] uvcvideo: Failed to query (135) UVC control 11 (unit 2) : -110 (exp. 1). > [ 2892.251617] uvcvideo: Failed to query (135) UVC control 4 (unit 2) : -110 (exp. 2). > [ 2892.579742] uvcvideo: Failed to query (135) UVC control 5 (unit 2) : -110 (exp. 1). > [ 2892.907867] uvcvideo: Failed to query (135) UVC control 8 (unit 2) : -110 (exp. 2). > [ 2893.235992] uvcvideo: Failed to query (135) UVC control 1 (unit 2) : -110 (exp. 2). > > The only way to bring it back - that I have found so far - is a system reboot. > Other USB devices connected to the same controller do not work after the camera fails which indicates a controller crash? > I have tried 6 other cameras that all have the same issue. > > I have been talking with Laurent Pinchart who maintains the UVC driver for Linux who suggested I contact the USB mailing list. > > Any ideas on a possible solution? > I suspect you're hitting a bug in the OMAP3. (Errata ID i572, see section 3.1.1.200 of the errata doc available at [1]). The errata description is not very clear, however the short summary is that if you're stressing the CAM/DSS domains, and doing lots of control transfers or short-packet transfers to a device connected to the EHCI controller, then you may end up locking up the EHCI. The only way to recover from this lockup is to soft-reset the USBHOST controller (which happens when you reboot, or if you rmmod and insmod the driver). The impact of this soft-reset is that you would necessarily have to reenumerate all devices connected to the EHCI/OHCI controllers. This bug is fixed in 3630/3730 ES1.2 and later. Ajay hacked together a recovery mechanism last week. I've looped him in, and attached his patch. Could you let us know if it works for you? - Anand [1] <http://focus.ti.com/lit/er/sprz278f/sprz278f.pdf>
>From e01db3a7a8312eaec60fe823a7ea51e8f2a3e97c Mon Sep 17 00:00:00 2001 From: Ajay Kumar Gupta <ajay.gupta@xxxxxx> Date: Fri, 31 Dec 2010 11:17:11 +0530 Subject: [PATCH 2/2] usb: ehci_omap: add recovery mechanism for omap3 errata Adding recovery mechanism for OMAP3x errata advisory 3.1.1.198: "USB Host EHCI May Stall when Running High Peak-bandwidth Demanding Use Cases" The recovery mechanism would reinitialize the EHCI controller whenever the stall scenario occurs. EHCI driver should be configured as builtin for recovery mechanism to be active. Signed-off-by: Ajay Kumar Gupta <ajay.gupta@xxxxxx> --- drivers/usb/core/hcd.c | 4 ++++ drivers/usb/core/hcd.h | 4 ++++ drivers/usb/core/message.c | 16 ++++++++++++++-- drivers/usb/host/ehci-hcd.c | 11 +++++++++-- drivers/usb/host/ehci-omap.c | 1 + 5 files changed, 32 insertions(+), 4 deletions(-) diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 6dac3b8..98f5518 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -2018,6 +2018,10 @@ struct usb_hcd *usb_create_hcd (const struct hc_driver *driver, hcd->driver = driver; hcd->product_desc = (driver->product_desc) ? driver->product_desc : "USB Host Controller"; + + /* ehci omap specific */ + INIT_WORK(&hcd->ehci_omap_work, hcd->driver->recover_hcd); + return hcd; } EXPORT_SYMBOL_GPL(usb_create_hcd); diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h index bbe2b92..62904e6 100644 --- a/drivers/usb/core/hcd.h +++ b/drivers/usb/core/hcd.h @@ -84,6 +84,7 @@ struct usb_hcd { struct work_struct wakeup_work; /* for remote wakeup */ #endif + struct work_struct ehci_omap_work; /* * hardware info/state */ @@ -245,6 +246,9 @@ struct hc_driver { void (*clear_tt_buffer_complete)(struct usb_hcd *, struct usb_host_endpoint *); + /* OMAP ehci controller specific */ + void (*recover_hcd)(struct work_struct *data); + /* xHCI specific functions */ /* Called by usb_alloc_dev to alloc HC device structures */ int (*alloc_dev)(struct usb_hcd *, struct usb_device *); diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index 1b99484..b586b72 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -95,10 +95,22 @@ static int usb_internal_control_msg(struct usb_device *usb_dev, len, usb_api_blocking_completion, NULL); retv = usb_start_wait_urb(urb, timeout, &length); - if (retv < 0) + if (retv < 0) { + struct usb_hcd *hcd = bus_to_hcd(usb_dev->bus); + + /* + * Recovery mechanism for OMAP3x errata Advisory 3.1.1.198 + * REVISIT: Check if control request are done using async + * API usb_submit_urb() instead of usb_control_msg(). + */ + if (!strcmp(hcd->product_desc, "OMAP-EHCI Host Controller") && + retv == -ETIMEDOUT && hcd->driver->recover_hcd) + queue_work(ksuspend_usb_wq, &hcd->ehci_omap_work); + return retv; - else + } else { return length; + } } /** diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 5859522..fb3248d 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -65,6 +65,8 @@ static const char hcd_name [] = "ehci_hcd"; +static void ehci_hcd_cleanup(void); +static int ehci_hcd_init(void); #undef VERBOSE_DEBUG #undef EHCI_URB_TRACE @@ -1091,6 +1093,11 @@ static int ehci_get_frame (struct usb_hcd *hcd) ehci->periodic_size; } +static void ehci_omap_recover_work(struct work_struct *data) +{ + ehci_hcd_cleanup(); + ehci_hcd_init(); +} /*-------------------------------------------------------------------------*/ MODULE_DESCRIPTION(DRIVER_DESC); @@ -1162,7 +1169,7 @@ MODULE_LICENSE ("GPL"); #error "missing bus glue for ehci-hcd" #endif -static int __init ehci_hcd_init(void) +static int ehci_hcd_init(void) { int retval = 0; @@ -1240,7 +1247,7 @@ err_debug: } module_init(ehci_hcd_init); -static void __exit ehci_hcd_cleanup(void) +static void ehci_hcd_cleanup(void) { #ifdef OF_PLATFORM_DRIVER of_unregister_platform_driver(&OF_PLATFORM_DRIVER); diff --git a/drivers/usb/host/ehci-omap.c b/drivers/usb/host/ehci-omap.c index 7d3a150..a8bb912 100644 --- a/drivers/usb/host/ehci-omap.c +++ b/drivers/usb/host/ehci-omap.c @@ -1160,6 +1160,7 @@ static const struct hc_driver ehci_omap_hc_driver = { .port_handed_over = ehci_port_handed_over, .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, + .recover_hcd = ehci_omap_recover_work, }; MODULE_ALIAS("platform:omap-ehci"); -- 1.6.2.4