usb: dwc2: host: process all completed urbs
authorGregory Herrero <gregory.herrero@intel.com>
Thu, 5 Nov 2015 08:41:45 +0000 (09:41 +0100)
committerFelipe Balbi <balbi@ti.com>
Tue, 15 Dec 2015 15:12:41 +0000 (09:12 -0600)
Process all completed urbs, if more urbs are complete by the time
driver processes completion interrupt.

Acked-by: John Youn <johnyoun@synopsys.com>
Signed-off-by: Gregory Herrero <gregory.herrero@intel.com>
Signed-off-by: Felipe Balbi <balbi@ti.com>
drivers/usb/dwc2/hcd_ddma.c

index edccac662d740a38386f0d4942ee14ff31d0de67..f98c7e91f6bcd2251785975289291a62dc9bef57 100644 (file)
@@ -940,17 +940,51 @@ static void dwc2_complete_isoc_xfer_ddma(struct dwc2_hsotg *hsotg,
        list_for_each_entry_safe(qtd, qtd_tmp, &qh->qtd_list, qtd_list_entry) {
                if (!qtd->in_process)
                        break;
+
+               /*
+                * Ensure idx corresponds to descriptor where first urb of this
+                * qtd was added. In fact, during isoc desc init, dwc2 may skip
+                * an index if current frame number is already over this index.
+                */
+               if (idx != qtd->isoc_td_first) {
+                       dev_vdbg(hsotg->dev,
+                                "try to complete %d instead of %d\n",
+                                idx, qtd->isoc_td_first);
+                       idx = qtd->isoc_td_first;
+               }
+
                do {
+                       struct dwc2_qtd *qtd_next;
+                       u16 cur_idx;
+
                        rc = dwc2_cmpl_host_isoc_dma_desc(hsotg, chan, qtd, qh,
                                                          idx);
                        if (rc < 0)
                                return;
                        idx = dwc2_desclist_idx_inc(idx, qh->interval,
                                                    chan->speed);
-                       if (rc == DWC2_CMPL_STOP)
-                               goto stop_scan;
+                       if (!rc)
+                               continue;
+
                        if (rc == DWC2_CMPL_DONE)
                                break;
+
+                       /* rc == DWC2_CMPL_STOP */
+
+                       if (qh->interval >= 32)
+                               goto stop_scan;
+
+                       qh->td_first = idx;
+                       cur_idx = dwc2_frame_list_idx(hsotg->frame_number);
+                       qtd_next = list_first_entry(&qh->qtd_list,
+                                                   struct dwc2_qtd,
+                                                   qtd_list_entry);
+                       if (dwc2_frame_idx_num_gt(cur_idx,
+                                                 qtd_next->isoc_td_last))
+                               break;
+
+                       goto stop_scan;
+
                } while (idx != qh->td_first);
        }