usb: dwc2: host: rework isochronous halt path
authorGregory Herrero <gregory.herrero@intel.com>
Thu, 5 Nov 2015 08:41:39 +0000 (09:41 +0100)
committerFelipe Balbi <balbi@ti.com>
Tue, 15 Dec 2015 15:12:41 +0000 (09:12 -0600)
When a channel is halted because of urb dequeue during transfer
completion, no other qtds must be scheduled until halt is done.
Moreover, all in progress qtds must be given back.

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 98d862726b5ab511e6ce0bc0e8c0cb36139fa35b..5f7265637334406dd4cfc11c3558618c9321dcde 100644 (file)
@@ -1161,6 +1161,21 @@ void dwc2_hcd_complete_xfer_ddma(struct dwc2_hsotg *hsotg,
                /* Release the channel if halted or session completed */
                if (halt_status != DWC2_HC_XFER_COMPLETE ||
                    list_empty(&qh->qtd_list)) {
+                       struct dwc2_qtd *qtd, *qtd_tmp;
+
+                       /*
+                        * Kill all remainings QTDs since channel has been
+                        * halted.
+                        */
+                       list_for_each_entry_safe(qtd, qtd_tmp,
+                                                &qh->qtd_list,
+                                                qtd_list_entry) {
+                               dwc2_host_complete(hsotg, qtd,
+                                                  -ECONNRESET);
+                               dwc2_hcd_qtd_unlink_and_free(hsotg,
+                                                            qtd, qh);
+                       }
+
                        /* Halt the channel if session completed */
                        if (halt_status == DWC2_HC_XFER_COMPLETE)
                                dwc2_hc_halt(hsotg, chan, halt_status);
@@ -1170,7 +1185,12 @@ void dwc2_hcd_complete_xfer_ddma(struct dwc2_hsotg *hsotg,
                        /* Keep in assigned schedule to continue transfer */
                        list_move(&qh->qh_list_entry,
                                  &hsotg->periodic_sched_assigned);
-                       continue_isoc_xfer = 1;
+                       /*
+                        * If channel has been halted during giveback of urb
+                        * then prevent any new scheduling.
+                        */
+                       if (!chan->halt_status)
+                               continue_isoc_xfer = 1;
                }
                /*
                 * Todo: Consider the case when period exceeds FrameList size.