[PATCH] staging: dwc2: always release host channel after dequeueing

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Matthijs Kooijman <matthijs@xxxxxxxx>

Previously, when an active urb was dequeued, its host channel would
not always be released. There is some special handling for this in
dwc2_hc_chhltd_intr_dma, but when it was the last urb/qtd in its qh, a
safeguard in dwc2_hc_n_intr would short-circuit and prevent the regular
interrupt handlers from running, without releasing the channel.

This is easily triggered when using a 3G modem using the option driver.
Opening and closing any ttyUSBx device will eat up a host channel that
is forever unusable from that point on.

Signed-off-by: Matthijs Kooijman <matthijs@xxxxxxxx>
[paulz@xxxxxxxxxxxx: fixed comment style and added a couple of NULL checks]
Signed-off-by: Paul Zimmerman <paulz@xxxxxxxxxxxx>
---
 drivers/staging/dwc2/hcd_intr.c | 33 +++++++++++++++++++++++++++++----
 1 file changed, 29 insertions(+), 4 deletions(-)

diff --git a/drivers/staging/dwc2/hcd_intr.c b/drivers/staging/dwc2/hcd_intr.c
index 4b007ab..8b68df8 100644
--- a/drivers/staging/dwc2/hcd_intr.c
+++ b/drivers/staging/dwc2/hcd_intr.c
@@ -708,7 +708,7 @@ static void dwc2_release_channel(struct dwc2_hsotg *hsotg,
 		free_qtd = 1;
 		break;
 	case DWC2_HC_XFER_XACT_ERR:
-		if (qtd->error_count >= 3) {
+		if (qtd && qtd->error_count >= 3) {
 			dev_vdbg(hsotg->dev,
 				 "  Complete URB with transaction error\n");
 			free_qtd = 1;
@@ -729,7 +729,7 @@ static void dwc2_release_channel(struct dwc2_hsotg *hsotg,
 	case DWC2_HC_XFER_PERIODIC_INCOMPLETE:
 		dev_vdbg(hsotg->dev, "  Complete URB with I/O error\n");
 		free_qtd = 1;
-		if (qtd->urb) {
+		if (qtd && qtd->urb) {
 			qtd->urb->status = -EIO;
 			dwc2_host_complete(hsotg, qtd->urb->priv, qtd->urb,
 					   -EIO);
@@ -1708,8 +1708,9 @@ static bool dwc2_halt_status_ok(struct dwc2_hsotg *hsotg,
 		dev_dbg(hsotg->dev,
 			"hcint 0x%08x, hcintmsk 0x%08x, hcsplt 0x%08x,\n",
 			chan->hcint, hcintmsk, hcsplt);
-		dev_dbg(hsotg->dev, "qtd->complete_split %d\n",
-			qtd->complete_split);
+		if (qtd)
+			dev_dbg(hsotg->dev, "qtd->complete_split %d\n",
+				qtd->complete_split);
 		dev_warn(hsotg->dev,
 			 "%s: no halt status, channel %d, ignoring interrupt\n",
 			 __func__, chnum);
@@ -1937,7 +1938,31 @@ static void dwc2_hc_n_intr(struct dwc2_hsotg *hsotg, int chnum)
 	chan->hcint = hcint;
 	hcint &= hcintmsk;
 
+	/*
+	 * If the channel was halted due to a dequeue, the qtd list might
+	 * be empty or at least the first entry will not be the active qtd.
+	 * In this case, take a shortcut and just release the channel.
+	 */
+	if (chan->halt_status == DWC2_HC_XFER_URB_DEQUEUE) {
+		/*
+		 * If the channel was halted, this should be the only
+		 * interrupt unmasked
+		 */
+		WARN_ON(hcint != HCINTMSK_CHHLTD);
+		if (hsotg->core_params->dma_desc_enable > 0)
+			dwc2_hcd_complete_xfer_ddma(hsotg, chan, chnum,
+						    chan->halt_status);
+		else
+			dwc2_release_channel(hsotg, chan, NULL,
+					     chan->halt_status);
+		return;
+	}
+
 	if (list_empty(&chan->qh->qtd_list)) {
+		/*
+		 * TODO: Will this ever happen with the
+		 * DWC2_HC_XFER_URB_DEQUEUE handling above?
+		 */
 		dev_dbg(hsotg->dev, "## no QTD queued for channel %d ##\n",
 			chnum);
 		dev_dbg(hsotg->dev,
-- 
1.8.2.rc0.16.g20a599e

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux