usb: dwc3: workaround: missing disconnect event
authorFelipe Balbi <balbi@ti.com>
Fri, 14 Oct 2011 12:11:49 +0000 (15:11 +0300)
committerFelipe Balbi <balbi@ti.com>
Mon, 12 Dec 2011 09:48:42 +0000 (11:48 +0200)
DWC3 revisions <1.88a have an issue which would
case a missing Disconnect event if cable is
disconnected while there's a Setup packet
pending the FIFO.

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

index b901a4d..836cf99 100644 (file)
@@ -578,6 +578,7 @@ struct dwc3_hwparams {
  * @ep0_bounced: true when we used bounce buffer
  * @ep0_expect_in: true when we expect a DATA IN transfer
  * @start_config_issued: true when StartConfig command has been issued
+ * @setup_packet_pending: true when there's a Setup Packet in FIFO. Workaround
  * @ep0_next_event: hold the next expected event
  * @ep0state: state of endpoint zero
  * @link_state: link state
@@ -633,6 +634,7 @@ struct dwc3 {
        unsigned                ep0_bounced:1;
        unsigned                ep0_expect_in:1;
        unsigned                start_config_issued:1;
+       unsigned                setup_packet_pending:1;
        unsigned                delayed_status:1;
 
        enum dwc3_ep0_next      ep0_next_event;
index 314acb2..ed44525 100644 (file)
@@ -625,6 +625,7 @@ static void dwc3_ep0_xfer_complete(struct dwc3 *dwc,
        struct dwc3_ep          *dep = dwc->eps[event->endpoint_number];
 
        dep->flags &= ~DWC3_EP_BUSY;
+       dwc->setup_packet_pending = false;
 
        switch (dwc->ep0state) {
        case EP0_SETUP_PHASE:
@@ -726,6 +727,8 @@ static void dwc3_ep0_do_control_status(struct dwc3 *dwc, u32 epnum)
 static void dwc3_ep0_xfernotready(struct dwc3 *dwc,
                const struct dwc3_event_depevt *event)
 {
+       dwc->setup_packet_pending = true;
+
        /*
         * This part is very tricky: If we has just handled
         * XferNotReady(Setup) and we're now expecting a
index 6704a52..7c98b3f 100644 (file)
@@ -1640,6 +1640,7 @@ static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc)
        dwc->start_config_issued = false;
 
        dwc->gadget.speed = USB_SPEED_UNKNOWN;
+       dwc->setup_packet_pending = false;
 }
 
 static void dwc3_gadget_usb3_phy_power(struct dwc3 *dwc, int on)
@@ -1676,6 +1677,37 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
 
        dev_vdbg(dwc->dev, "%s\n", __func__);
 
+       /*
+        * WORKAROUND: DWC3 revisions <1.88a have an issue which
+        * would cause a missing Disconnect Event if there's a
+        * pending Setup Packet in the FIFO.
+        *
+        * There's no suggested workaround on the official Bug
+        * report, which states that "unless the driver/application
+        * is doing any special handling of a disconnect event,
+        * there is no functional issue".
+        *
+        * Unfortunately, it turns out that we _do_ some special
+        * handling of a disconnect event, namely complete all
+        * pending transfers, notify gadget driver of the
+        * disconnection, and so on.
+        *
+        * Our suggested workaround is to follow the Disconnect
+        * Event steps here, instead, based on a setup_packet_pending
+        * flag. Such flag gets set whenever we have a XferNotReady
+        * event on EP0 and gets cleared on XferComplete for the
+        * same endpoint.
+        *
+        * Refers to:
+        *
+        * STAR#9000466709: RTL: Device : Disconnect event not
+        * generated if setup packet pending in FIFO
+        */
+       if (dwc->revision < DWC3_REVISION_188A) {
+               if (dwc->setup_packet_pending)
+                       dwc3_gadget_disconnect_interrupt(dwc);
+       }
+
        /* Enable PHYs */
        dwc3_gadget_usb2_phy_power(dwc, true);
        dwc3_gadget_usb3_phy_power(dwc, true);