]> rtime.felk.cvut.cz Git - vajnamar/linux-xlnx.git/commitdiff
usb: dwc3: implement stream transfer timout
authorRajnikant Bhojani <rajnikant.bhojani@xilinx.com>
Fri, 11 Aug 2017 08:54:19 +0000 (04:54 -0400)
committerMichal Simek <michal.simek@xilinx.com>
Tue, 15 Aug 2017 10:57:01 +0000 (12:57 +0200)
according to databook it may be possible host and device become
out of sync where device wait for host to issue prime transcation
and host waits for device to issue erdy to avoid such deadlock
timeout need to be implement. after timeout device will first
stop transfer and again restart the transfer

Signed-off-by: Rajnikant Bhojani <rajnikant.bhojani@xilinx.com>
Signed-off-by: Michal Simek <michal.simek@xilinx.com>
drivers/usb/dwc3/core.h
drivers/usb/dwc3/gadget.c

index 264df38a7cb6752eecb963f4615beef84cb1a8f0..a361417a0d2cd9bfb6e452d001f631b42245e919 100644 (file)
@@ -581,6 +581,8 @@ struct dwc3_ep {
 
        unsigned                direction:1;
        unsigned                stream_capable:1;
+#define STREAM_TIMEOUT         50
+       struct timer_list       stream_timeout_timer;
 };
 
 enum dwc3_phy {
index e740a925a2a3a5a8f26cf9893699f47a8799b6b8..bda55a19c86049ba6bd7c6ceaf7868624244ce2e 100644 (file)
@@ -453,6 +453,20 @@ static int dwc3_gadget_start_config(struct dwc3 *dwc, struct dwc3_ep *dep)
        return 0;
 }
 
+static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum, bool force);
+static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param);
+static void stream_timeout_function(unsigned long arg)
+{
+       struct dwc3_ep *dep = (struct dwc3_ep *)arg;
+       struct dwc3             *dwc = dep->dwc;
+       unsigned long           flags;
+
+       spin_lock_irqsave(&dwc->lock, flags);
+       dwc3_stop_active_transfer(dwc, dep->number, true);
+       __dwc3_gadget_kick_transfer(dep, 0);
+       spin_unlock_irqrestore(&dwc->lock, flags);
+}
+
 static int dwc3_gadget_set_ep_config(struct dwc3 *dwc, struct dwc3_ep *dep,
                const struct usb_endpoint_descriptor *desc,
                const struct usb_ss_ep_comp_descriptor *comp_desc,
@@ -495,6 +509,8 @@ static int dwc3_gadget_set_ep_config(struct dwc3 *dwc, struct dwc3_ep *dep,
                        | DWC3_DEPCFG_STREAM_EVENT_EN
                        | DWC3_DEPCFG_XFER_COMPLETE_EN;
                dep->stream_capable = true;
+               setup_timer(&dep->stream_timeout_timer,
+                           stream_timeout_function, (unsigned long)dep);
        }
 
        if (!usb_endpoint_xfer_control(desc))
@@ -635,6 +651,9 @@ int __dwc3_gadget_ep_disable(struct dwc3_ep *dep)
 
        dwc3_trace(trace_dwc3_gadget, "Disabling %s", dep->name);
 
+       if (dep->stream_capable)
+               del_timer(&dep->stream_timeout_timer);
+
        dwc3_remove_requests(dwc, dep);
 
        /* make sure HW endpoint isn't stalled */
@@ -1011,6 +1030,11 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param)
        dep->flags |= DWC3_EP_BUSY;
 
        if (starting) {
+               if (dep->stream_capable) {
+                       dep->stream_timeout_timer.expires = jiffies +
+                                       msecs_to_jiffies(STREAM_TIMEOUT);
+                       add_timer(&dep->stream_timeout_timer);
+               }
                dep->resource_index = dwc3_gadget_ep_get_transfer_index(dep);
                WARN_ON_ONCE(!dep->resource_index);
        }
@@ -2186,6 +2210,7 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
 
                switch (event->status) {
                case DEPEVT_STREAMEVT_FOUND:
+                       del_timer(&dep->stream_timeout_timer);
                        dwc3_trace(trace_dwc3_gadget,
                                        "Stream %d found and started",
                                        event->parameters);