aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDouglas Anderson <dianders@chromium.org>2016-01-28 21:20:03 -0500
committerFelipe Balbi <balbi@kernel.org>2016-03-04 08:14:42 -0500
commit4e50e0110c5cdc6d361b813692857e09ec918c9d (patch)
treeb38a1249185936f6cb447991602babc342c9154c
parentd82a810eede9c324d8353edde79b7e316f145f87 (diff)
usb: dwc2: host: Use periodic interrupt even with DMA
The old code in dwc2_process_periodic_channels() would only enable the "periodic empty" interrupt if we weren't using DMA. That wasn't right since we can still get into cases where we have small FIFOs even on systems that have DMA (the rk3288 is a prime example). Let's always enable/disable the "periodic empty" when appropriate. As part of this: * Always call dwc2_process_periodic_channels() even if there's nothing in periodic_sched_assigned (we move the queue empty check so we still avoid the extra work). That will make extra certain that we will properly disable the "periodic empty" interrupt even if there's nothing queued up. * Move the enable of "periodic empty" due to non-empty periodic_sched_assigned to be for slave mode (non-DMA mode) only. Presumably this was the original intention of the check for DMA since it seems to match the comments above where in slave mode we leave things on the assigned queue. Note that even before this change slave mode didn't work for me, so I can't say for sure that my understanding of slave mode is correct. However, this shouldn't change anything for slave mode so if slave mode worked for someone in the past it ought to still work. With this change, I no longer get constant misses reported by my other debugging code (and with future patches) when I've got: * Rockchip rk3288 Chromebook, using port ff540000 -> Pluggable 7-port Hub with Charging (powered) -> Microsoft Wireless Keyboard 2000 in port 1. -> Das Keyboard in port 2. -> Jabra Speaker in port 3 -> Logitech, Inc. Webcam C600 in port 4 -> Microsoft Sidewinder X6 Keyboard in port 5 ...and I'm playing music on the USB speaker and capturing video from the webcam. Acked-by: John Youn <johnyoun@synopsys.com> Signed-off-by: Douglas Anderson <dianders@chromium.org> Tested-by: Heiko Stuebner <heiko@sntech.de> Tested-by: Stefan Wahren <stefan.wahren@i2se.com> Signed-off-by: Felipe Balbi <balbi@kernel.org>
-rw-r--r--drivers/usb/dwc2/hcd.c71
1 files changed, 32 insertions, 39 deletions
diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
index 40558478a192..fd731347daf7 100644
--- a/drivers/usb/dwc2/hcd.c
+++ b/drivers/usb/dwc2/hcd.c
@@ -1109,10 +1109,14 @@ static void dwc2_process_periodic_channels(struct dwc2_hsotg *hsotg)
1109 u32 fspcavail; 1109 u32 fspcavail;
1110 u32 gintmsk; 1110 u32 gintmsk;
1111 int status; 1111 int status;
1112 int no_queue_space = 0; 1112 bool no_queue_space = false;
1113 int no_fifo_space = 0; 1113 bool no_fifo_space = false;
1114 u32 qspcavail; 1114 u32 qspcavail;
1115 1115
1116 /* If empty list then just adjust interrupt enables */
1117 if (list_empty(&hsotg->periodic_sched_assigned))
1118 goto exit;
1119
1116 if (dbg_perio()) 1120 if (dbg_perio())
1117 dev_vdbg(hsotg->dev, "Queue periodic transactions\n"); 1121 dev_vdbg(hsotg->dev, "Queue periodic transactions\n");
1118 1122
@@ -1190,42 +1194,32 @@ static void dwc2_process_periodic_channels(struct dwc2_hsotg *hsotg)
1190 } 1194 }
1191 } 1195 }
1192 1196
1193 if (hsotg->core_params->dma_enable <= 0) { 1197exit:
1194 tx_status = dwc2_readl(hsotg->regs + HPTXSTS); 1198 if (no_queue_space || no_fifo_space ||
1195 qspcavail = (tx_status & TXSTS_QSPCAVAIL_MASK) >> 1199 (hsotg->core_params->dma_enable <= 0 &&
1196 TXSTS_QSPCAVAIL_SHIFT; 1200 !list_empty(&hsotg->periodic_sched_assigned))) {
1197 fspcavail = (tx_status & TXSTS_FSPCAVAIL_MASK) >> 1201 /*
1198 TXSTS_FSPCAVAIL_SHIFT; 1202 * May need to queue more transactions as the request
1199 if (dbg_perio()) { 1203 * queue or Tx FIFO empties. Enable the periodic Tx
1200 dev_vdbg(hsotg->dev, 1204 * FIFO empty interrupt. (Always use the half-empty
1201 " P Tx Req Queue Space Avail (after queue): %d\n", 1205 * level to ensure that new requests are loaded as
1202 qspcavail); 1206 * soon as possible.)
1203 dev_vdbg(hsotg->dev, 1207 */
1204 " P Tx FIFO Space Avail (after queue): %d\n", 1208 gintmsk = dwc2_readl(hsotg->regs + GINTMSK);
1205 fspcavail); 1209 if (!(gintmsk & GINTSTS_PTXFEMP)) {
1206 }
1207
1208 if (!list_empty(&hsotg->periodic_sched_assigned) ||
1209 no_queue_space || no_fifo_space) {
1210 /*
1211 * May need to queue more transactions as the request
1212 * queue or Tx FIFO empties. Enable the periodic Tx
1213 * FIFO empty interrupt. (Always use the half-empty
1214 * level to ensure that new requests are loaded as
1215 * soon as possible.)
1216 */
1217 gintmsk = dwc2_readl(hsotg->regs + GINTMSK);
1218 gintmsk |= GINTSTS_PTXFEMP; 1210 gintmsk |= GINTSTS_PTXFEMP;
1219 dwc2_writel(gintmsk, hsotg->regs + GINTMSK); 1211 dwc2_writel(gintmsk, hsotg->regs + GINTMSK);
1220 } else { 1212 }
1221 /* 1213 } else {
1222 * Disable the Tx FIFO empty interrupt since there are 1214 /*
1223 * no more transactions that need to be queued right 1215 * Disable the Tx FIFO empty interrupt since there are
1224 * now. This function is called from interrupt 1216 * no more transactions that need to be queued right
1225 * handlers to queue more transactions as transfer 1217 * now. This function is called from interrupt
1226 * states change. 1218 * handlers to queue more transactions as transfer
1227 */ 1219 * states change.
1228 gintmsk = dwc2_readl(hsotg->regs + GINTMSK); 1220 */
1221 gintmsk = dwc2_readl(hsotg->regs + GINTMSK);
1222 if (gintmsk & GINTSTS_PTXFEMP) {
1229 gintmsk &= ~GINTSTS_PTXFEMP; 1223 gintmsk &= ~GINTSTS_PTXFEMP;
1230 dwc2_writel(gintmsk, hsotg->regs + GINTMSK); 1224 dwc2_writel(gintmsk, hsotg->regs + GINTMSK);
1231 } 1225 }
@@ -1372,9 +1366,8 @@ void dwc2_hcd_queue_transactions(struct dwc2_hsotg *hsotg,
1372 dev_vdbg(hsotg->dev, "Queue Transactions\n"); 1366 dev_vdbg(hsotg->dev, "Queue Transactions\n");
1373#endif 1367#endif
1374 /* Process host channels associated with periodic transfers */ 1368 /* Process host channels associated with periodic transfers */
1375 if ((tr_type == DWC2_TRANSACTION_PERIODIC || 1369 if (tr_type == DWC2_TRANSACTION_PERIODIC ||
1376 tr_type == DWC2_TRANSACTION_ALL) && 1370 tr_type == DWC2_TRANSACTION_ALL)
1377 !list_empty(&hsotg->periodic_sched_assigned))
1378 dwc2_process_periodic_channels(hsotg); 1371 dwc2_process_periodic_channels(hsotg);
1379 1372
1380 /* Process host channels associated with non-periodic transfers */ 1373 /* Process host channels associated with non-periodic transfers */