]> git.openfabrics.org - ~emulex/infiniband.git/commitdiff
usb: dwc3: workaround: bogus hibernation events
authorFelipe Balbi <balbi@ti.com>
Tue, 25 Feb 2014 20:47:54 +0000 (14:47 -0600)
committerFelipe Balbi <balbi@ti.com>
Wed, 5 Mar 2014 15:44:50 +0000 (09:44 -0600)
Revision 2.20a of the core has a known issue
which would generate bogus hibernation events
_and_ random failures on USB CV TD.9.23 test
case.

The suggested workaround is to ignore hibernation
events which don't match currently connected
speed.

Signed-off-by: Felipe Balbi <balbi@ti.com>
drivers/usb/dwc3/gadget.c

index 9e878d9bc909ec67a13aa3c9b10e3a4373e80eaf..7f4e6dd63c00067120ab293dc893e88cfca15d0a 100644 (file)
@@ -2378,6 +2378,30 @@ static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc,
        dev_vdbg(dwc->dev, "%s link %d\n", __func__, dwc->link_state);
 }
 
+static void dwc3_gadget_hibernation_interrupt(struct dwc3 *dwc,
+               unsigned int evtinfo)
+{
+       unsigned int is_ss = evtinfo & BIT(4);
+
+       /**
+        * WORKAROUND: DWC3 revison 2.20a with hibernation support
+        * have a known issue which can cause USB CV TD.9.23 to fail
+        * randomly.
+        *
+        * Because of this issue, core could generate bogus hibernation
+        * events which SW needs to ignore.
+        *
+        * Refers to:
+        *
+        * STAR#9000546576: Device Mode Hibernation: Issue in USB 2.0
+        * Device Fallback from SuperSpeed
+        */
+       if (is_ss ^ (dwc->speed == USB_SPEED_SUPER))
+               return;
+
+       /* enter hibernation here */
+}
+
 static void dwc3_gadget_interrupt(struct dwc3 *dwc,
                const struct dwc3_event_devt *event)
 {
@@ -2394,6 +2418,13 @@ static void dwc3_gadget_interrupt(struct dwc3 *dwc,
        case DWC3_DEVICE_EVENT_WAKEUP:
                dwc3_gadget_wakeup_interrupt(dwc);
                break;
+       case DWC3_DEVICE_EVENT_HIBER_REQ:
+               if (dev_WARN_ONCE(dwc->dev, !dwc->has_hibernation,
+                                       "unexpected hibernation event\n"))
+                       break;
+
+               dwc3_gadget_hibernation_interrupt(dwc, event->event_info);
+               break;
        case DWC3_DEVICE_EVENT_LINK_STATUS_CHANGE:
                dwc3_gadget_linksts_change_interrupt(dwc, event->event_info);
                break;