浏览代码

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>
Gregory Herrero 9 年之前
父节点
当前提交
c503b38153
共有 1 个文件被更改,包括 21 次插入1 次删除
  1. 21 1
      drivers/usb/dwc2/hcd_ddma.c

+ 21 - 1
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 */
 		/* Release the channel if halted or session completed */
 		if (halt_status != DWC2_HC_XFER_COMPLETE ||
 		if (halt_status != DWC2_HC_XFER_COMPLETE ||
 		    list_empty(&qh->qtd_list)) {
 		    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 */
 			/* Halt the channel if session completed */
 			if (halt_status == DWC2_HC_XFER_COMPLETE)
 			if (halt_status == DWC2_HC_XFER_COMPLETE)
 				dwc2_hc_halt(hsotg, chan, halt_status);
 				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 */
 			/* Keep in assigned schedule to continue transfer */
 			list_move(&qh->qh_list_entry,
 			list_move(&qh->qh_list_entry,
 				  &hsotg->periodic_sched_assigned);
 				  &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.
 		 * Todo: Consider the case when period exceeds FrameList size.