diff options
author | Gregory Herrero <gregory.herrero@intel.com> | 2015-11-05 11:41:39 +0300 |
---|---|---|
committer | Felipe Balbi <balbi@ti.com> | 2015-12-15 18:12:41 +0300 |
commit | c503b38153852d88774b54ae17f7723f68c6dc33 (patch) | |
tree | b8c1fa6d6ab56059f94a6bece12c6683369bee62 /drivers/usb/dwc2/hcd_ddma.c | |
parent | dde4c1bf5df0f852e497e5644d3578885b969fdb (diff) | |
download | linux-c503b38153852d88774b54ae17f7723f68c6dc33.tar.xz |
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.c | 22 |
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. |