Commit 8509f2f4 authored by Matthijs Kooijman's avatar Matthijs Kooijman Committed by Greg Kroah-Hartman

staging: dwc2: always release host channel after dequeueing

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: default avatarMatthijs Kooijman <matthijs@stdin.nl>
[paulz@synopsys.com: fixed comment style and added a couple of NULL checks]
Signed-off-by: default avatarPaul Zimmerman <paulz@synopsys.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 257f6580
...@@ -708,7 +708,7 @@ static void dwc2_release_channel(struct dwc2_hsotg *hsotg, ...@@ -708,7 +708,7 @@ static void dwc2_release_channel(struct dwc2_hsotg *hsotg,
free_qtd = 1; free_qtd = 1;
break; break;
case DWC2_HC_XFER_XACT_ERR: case DWC2_HC_XFER_XACT_ERR:
if (qtd->error_count >= 3) { if (qtd && qtd->error_count >= 3) {
dev_vdbg(hsotg->dev, dev_vdbg(hsotg->dev,
" Complete URB with transaction error\n"); " Complete URB with transaction error\n");
free_qtd = 1; free_qtd = 1;
...@@ -729,7 +729,7 @@ static void dwc2_release_channel(struct dwc2_hsotg *hsotg, ...@@ -729,7 +729,7 @@ static void dwc2_release_channel(struct dwc2_hsotg *hsotg,
case DWC2_HC_XFER_PERIODIC_INCOMPLETE: case DWC2_HC_XFER_PERIODIC_INCOMPLETE:
dev_vdbg(hsotg->dev, " Complete URB with I/O error\n"); dev_vdbg(hsotg->dev, " Complete URB with I/O error\n");
free_qtd = 1; free_qtd = 1;
if (qtd->urb) { if (qtd && qtd->urb) {
qtd->urb->status = -EIO; qtd->urb->status = -EIO;
dwc2_host_complete(hsotg, qtd->urb->priv, qtd->urb, dwc2_host_complete(hsotg, qtd->urb->priv, qtd->urb,
-EIO); -EIO);
...@@ -1708,6 +1708,7 @@ static bool dwc2_halt_status_ok(struct dwc2_hsotg *hsotg, ...@@ -1708,6 +1708,7 @@ static bool dwc2_halt_status_ok(struct dwc2_hsotg *hsotg,
dev_dbg(hsotg->dev, dev_dbg(hsotg->dev,
"hcint 0x%08x, hcintmsk 0x%08x, hcsplt 0x%08x,\n", "hcint 0x%08x, hcintmsk 0x%08x, hcsplt 0x%08x,\n",
chan->hcint, hcintmsk, hcsplt); chan->hcint, hcintmsk, hcsplt);
if (qtd)
dev_dbg(hsotg->dev, "qtd->complete_split %d\n", dev_dbg(hsotg->dev, "qtd->complete_split %d\n",
qtd->complete_split); qtd->complete_split);
dev_warn(hsotg->dev, dev_warn(hsotg->dev,
...@@ -1937,7 +1938,31 @@ static void dwc2_hc_n_intr(struct dwc2_hsotg *hsotg, int chnum) ...@@ -1937,7 +1938,31 @@ static void dwc2_hc_n_intr(struct dwc2_hsotg *hsotg, int chnum)
chan->hcint = hcint; chan->hcint = hcint;
hcint &= hcintmsk; 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)) { 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", dev_dbg(hsotg->dev, "## no QTD queued for channel %d ##\n",
chnum); chnum);
dev_dbg(hsotg->dev, dev_dbg(hsotg->dev,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment