summaryrefslogtreecommitdiff
path: root/drivers/usb/dwc2/hcd_ddma.c
diff options
context:
space:
mode:
authorGregory Herrero <gregory.herrero@intel.com>2015-11-05 09:41:39 +0100
committerFelipe Balbi <balbi@ti.com>2015-12-15 09:12:41 -0600
commitc503b38153852d88774b54ae17f7723f68c6dc33 (patch)
treeb8c1fa6d6ab56059f94a6bece12c6683369bee62 /drivers/usb/dwc2/hcd_ddma.c
parentdde4c1bf5df0f852e497e5644d3578885b969fdb (diff)
usb: dwc2: host: rework isochronous halt path
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>
Diffstat (limited to 'drivers/usb/dwc2/hcd_ddma.c')
-rw-r--r--drivers/usb/dwc2/hcd_ddma.c22
1 files changed, 21 insertions, 1 deletions
diff --git a/drivers/usb/dwc2/hcd_ddma.c b/drivers/usb/dwc2/hcd_ddma.c
index 98d862726b5a..5f7265637334 100644
--- a/drivers/usb/dwc2/hcd_ddma.c
+++ b/drivers/usb/dwc2/hcd_ddma.c
@@ -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.