Disable NAK timeout on bulk transfers, I couldn't find a way to clear trunk
authorbouyer <bouyer@NetBSD.org>
Sat, 19 Jul 2014 22:08:54 +0000
branchtrunk
changeset 228589 925bd0928f69
parent 228588 25d2a856c1ac
child 228590 8200d1f89dab
Disable NAK timeout on bulk transfers, I couldn't find a way to clear the NAK bit not the FIFO. Make xfer aborts more robust to races, by setting proper status and flags in xfer.
sys/dev/usb/motg.c
--- a/sys/dev/usb/motg.c	Sat Jul 19 21:22:58 2014 +0000
+++ b/sys/dev/usb/motg.c	Sat Jul 19 22:08:54 2014 +0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: motg.c,v 1.2 2014/07/17 19:58:18 bouyer Exp $	*/
+/*	$NetBSD: motg.c,v 1.3 2014/07/19 22:08:54 bouyer Exp $	*/
 
 /*
  * Copyright (c) 1998, 2004, 2011, 2012, 2014 The NetBSD Foundation, Inc.
@@ -40,7 +40,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: motg.c,v 1.2 2014/07/17 19:58:18 bouyer Exp $");
+__KERNEL_RCSID(0, "$NetBSD: motg.c,v 1.3 2014/07/19 22:08:54 bouyer Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -90,8 +90,8 @@
 #define POLL_TO_HIGH	10	/* 100 microframes, about 0.12s */
 
 /* bulk NAK timeouts */
-#define NAK_TO_BULK	255	/* 255 frames, about 0.25s */
-#define NAK_TO_BULK_HIGH 13	/* 8k microframes, about 1s */
+#define NAK_TO_BULK	0 /* disabled */
+#define NAK_TO_BULK_HIGH 0
 
 static void 		motg_hub_change(struct motg_softc *);
 static usbd_status	motg_root_ctrl_transfer(usbd_xfer_handle);
@@ -140,7 +140,8 @@
 static void		motg_device_data_write(usbd_xfer_handle);
 
 static void		motg_waitintr(struct motg_softc *, usbd_xfer_handle);
-static void		motg_device_clear_toggle(usbd_pipe_handle pipe);
+static void		motg_device_clear_toggle(usbd_pipe_handle);
+static void		motg_device_xfer_abort(usbd_xfer_handle);
 
 #define MOTG_INTR_ENDPT 1
 #define UBARR(sc) bus_space_barrier((sc)->sc_iot, (sc)->sc_ioh, 0, (sc)->sc_size, \
@@ -352,13 +353,17 @@
 			if (fiforx_size && (i <= nrx)) {
 				fiforx_size = fifo_size;
 				if (fifo_size > 7) {
+#if 0
 					UWRITE1(sc, MUSB2_REG_RXFIFOSZ,  
 					    MUSB2_VAL_FIFOSZ(fifo_size) |
 					    MUSB2_MASK_FIFODB);
+#else
+					UWRITE1(sc, MUSB2_REG_RXFIFOSZ,  
+					    MUSB2_VAL_FIFOSZ(fifo_size));
+#endif
 				} else {
 					UWRITE1(sc, MUSB2_REG_RXFIFOSZ,  
-					    MUSB2_VAL_FIFOSZ(fifo_size) |
-					    MUSB2_MASK_FIFODB);
+					    MUSB2_VAL_FIFOSZ(fifo_size));
 				}
 				UWRITE2(sc, MUSB2_REG_RXFIFOADD,  
 				    offset >> 3);
@@ -367,9 +372,14 @@
 			if (fifotx_size && (i <= ntx)) {
 				fifotx_size = fifo_size;
 				if (fifo_size > 7) {
+#if 0
 					UWRITE1(sc, MUSB2_REG_TXFIFOSZ,  
 					    MUSB2_VAL_FIFOSZ(fifo_size) |     
 					    MUSB2_MASK_FIFODB);
+#else
+					UWRITE1(sc, MUSB2_REG_TXFIFOSZ,  
+					    MUSB2_VAL_FIFOSZ(fifo_size));      
+#endif
 				} else {
 					UWRITE1(sc, MUSB2_REG_TXFIFOSZ,  
 					    MUSB2_VAL_FIFOSZ(fifo_size));      
@@ -639,7 +649,6 @@
 		if (tx_status & (0x01 << i))
 			motg_device_intr_tx(sc, i);
 	}
-
 	return;
 }
 
@@ -1075,12 +1084,6 @@
 			change |= UPS_C_PORT_ENABLED;
 			sc->sc_port_enabled_changed = 0;
 		}
-#if 0 /*XXX*/
-		if (x & MOTG_PORTSC_OCI)
-			status |= UPS_OVERCURRENT_INDICATOR;
-		if (x & MOTG_PORTSC_OCIC)
-			change |= UPS_C_OVERCURRENT_INDICATOR;
-#endif
 		if (sc->sc_port_suspended)
 			status |= UPS_SUSPEND;
 		if (sc->sc_high_speed)
@@ -1448,6 +1451,7 @@
 	/* Insert last in queue. */
 	mutex_enter(&sc->sc_lock);
 	err = usb_insert_transfer(xfer);
+	xfer->status = USBD_NOT_STARTED;
 	mutex_exit(&sc->sc_lock);
 	if (err)
 		return (err);
@@ -1478,7 +1482,7 @@
 motg_device_ctrl_start1(struct motg_softc *sc)
 {
 	struct motg_hw_ep *ep = &sc->sc_in_ep[0];
-	usbd_xfer_handle xfer;
+	usbd_xfer_handle xfer = NULL;
 	struct motg_pipe *otgpipe;
 	usbd_status err = 0;
 
@@ -1496,6 +1500,10 @@
 	/* locate the first pipe with work to do */
 	SIMPLEQ_FOREACH(otgpipe, &ep->ep_pipes, ep_pipe_list) {
 		xfer = SIMPLEQ_FIRST(&otgpipe->pipe.queue);
+		DPRINTFN(MD_CTRL,
+		    ("motg_device_ctrl_start1 pipe %p xfer %p status %d\n",
+		    otgpipe, xfer, (xfer != NULL) ? xfer->status : 0));
+		    
 		if (xfer != NULL) {
 			/* move this pipe to the end of the list */
 			SIMPLEQ_REMOVE(&ep->ep_pipes, otgpipe,
@@ -1509,7 +1517,7 @@
 		err = USBD_NOT_STARTED;
 		goto end;
 	}
-	KASSERT(xfer != NULL);
+	xfer->status = USBD_IN_PROGRESS;
 	KASSERT(otgpipe == (struct motg_pipe *)xfer->pipe);
 	KASSERT(otgpipe->hw_ep == ep);
 #ifdef DIAGNOSTIC
@@ -1580,6 +1588,7 @@
 	int datalen, max_datalen;
 	char *data;
 	bool got_short;
+	usbd_status new_status = USBD_IN_PROGRESS;
 
 	KASSERT(mutex_owned(&sc->sc_lock));
 
@@ -1594,8 +1603,8 @@
 	/* read out FIFO status */
 	csr = UREAD1(sc, MUSB2_REG_TXCSRL);
 	DPRINTFN(MD_CTRL, 
-	    ("motg_device_ctrl_intr_rx phase %d csr 0x%x\n", 
-	    ep->phase, csr));
+	    ("motg_device_ctrl_intr_rx phase %d csr 0x%x xfer %p status %d\n", 
+	    ep->phase, csr, xfer, (xfer != NULL) ? xfer->status : 0));
 
 	if (csr & MUSB2_MASK_CSR0L_NAKTIMO) {
 		csr &= ~MUSB2_MASK_CSR0L_REQPKT;
@@ -1603,17 +1612,14 @@
 
 		csr &= ~MUSB2_MASK_CSR0L_NAKTIMO;
 		UWRITE1(sc, MUSB2_REG_TXCSRL, csr);
-		if (xfer)
-			xfer->status = USBD_TIMEOUT; /* XXX */
+		new_status = USBD_TIMEOUT; /* XXX */
 		goto complete;
 	}
 	if (csr & (MUSB2_MASK_CSR0L_RXSTALL | MUSB2_MASK_CSR0L_ERROR)) {
-		if (xfer) {
-			if (csr & MUSB2_MASK_CSR0L_RXSTALL)
-				xfer->status = USBD_STALLED;
-			else
-				xfer->status = USBD_IOERROR;
-		}
+		if (csr & MUSB2_MASK_CSR0L_RXSTALL)
+			new_status = USBD_STALLED;
+		else
+			new_status = USBD_IOERROR;
 		/* clear status */
 		UWRITE1(sc, MUSB2_REG_TXCSRL, 0);
 		goto complete;
@@ -1621,11 +1627,11 @@
 	if ((csr & MUSB2_MASK_CSR0L_RXPKTRDY) == 0)
 		return; /* no data yet */
 
-	if (xfer == NULL)
+	if (xfer == NULL || xfer->status != USBD_IN_PROGRESS)
 		goto complete;
 
 	if (ep->phase == STATUS_IN) {
-		xfer->status = USBD_NORMAL_COMPLETION;
+		new_status = USBD_NORMAL_COMPLETION;
 		UWRITE1(sc, MUSB2_REG_TXCSRL, 0);
 		goto complete;
 	}
@@ -1637,7 +1643,7 @@
 	max_datalen = min(UGETW(xfer->pipe->endpoint->edesc->wMaxPacketSize),
 	    ep->datalen);
 	if (datalen > max_datalen) {
-		xfer->status = USBD_IOERROR;
+		new_status = USBD_IOERROR;
 		UWRITE1(sc, MUSB2_REG_TXCSRL, 0);
 		goto complete;
 	}
@@ -1687,8 +1693,11 @@
 complete:
 	ep->phase = IDLE;
 	ep->xfer = NULL;
-	if (xfer)
+	if (xfer && xfer->status == USBD_IN_PROGRESS) {
+		KASSERT(new_status != USBD_IN_PROGRESS);
+		xfer->status = new_status;
 		usb_transfer_complete(xfer);
+	}
 	motg_device_ctrl_start1(sc);
 }
 
@@ -1700,6 +1709,7 @@
 	uint8_t csr;
 	int datalen;
 	char *data;
+	usbd_status new_status = USBD_IN_PROGRESS;
 
 	KASSERT(mutex_owned(&sc->sc_lock));
 	if (ep->phase == DATA_IN || ep->phase == STATUS_IN) {
@@ -1717,20 +1727,18 @@
 
 	csr = UREAD1(sc, MUSB2_REG_TXCSRL);
 	DPRINTFN(MD_CTRL, 
-	    ("motg_device_ctrl_intr_tx phase %d csr 0x%x\n", 
-	    ep->phase, csr));
+	    ("motg_device_ctrl_intr_tx phase %d csr 0x%x xfer %p status %d\n", 
+	    ep->phase, csr, xfer, (xfer != NULL) ? xfer->status : 0));
 
 	if (csr & MUSB2_MASK_CSR0L_RXSTALL) {
 		/* command not accepted */
-		if (xfer)
-			xfer->status = USBD_STALLED;
+		new_status = USBD_STALLED;
 		/* clear status */
 		UWRITE1(sc, MUSB2_REG_TXCSRL, 0);
 		goto complete;
 	}
 	if (csr & MUSB2_MASK_CSR0L_NAKTIMO) {
-		if (xfer)
-			xfer->status = USBD_TIMEOUT; /* XXX */
+		new_status = USBD_TIMEOUT; /* XXX */
 		/* flush fifo */
 		while (csr & MUSB2_MASK_CSR0L_TXFIFONEMPTY) {
 			UWRITE1(sc, MUSB2_REG_TXCSRH,
@@ -1743,8 +1751,7 @@
 		goto complete;
 	}
 	if (csr & MUSB2_MASK_CSR0L_ERROR) {
-		if (xfer)
-			xfer->status = USBD_IOERROR;
+		new_status = USBD_IOERROR;
 		/* clear status */
 		UWRITE1(sc, MUSB2_REG_TXCSRL, 0);
 		goto complete;
@@ -1761,8 +1768,9 @@
 		 * declare transfer complete
 		 */
 		DPRINTFN(MD_CTRL, 
-		    ("motg_device_ctrl_intr_tx %p complete\n", xfer));
-		xfer->status = USBD_NORMAL_COMPLETION;
+		    ("motg_device_ctrl_intr_tx %p status %d complete\n",
+			xfer, xfer->status));
+		new_status = USBD_NORMAL_COMPLETION;
 		goto complete;
 	}
 	if (ep->datalen == 0) {
@@ -1826,8 +1834,11 @@
 complete:
 	ep->phase = IDLE;
 	ep->xfer = NULL;
-	if (xfer)
+	if (xfer && xfer->status == USBD_IN_PROGRESS) {
+		KASSERT(new_status != USBD_IN_PROGRESS);
+		xfer->status = new_status;
 		usb_transfer_complete(xfer);
+	}
 	motg_device_ctrl_start1(sc);
 }
 
@@ -1835,17 +1846,8 @@
 void
 motg_device_ctrl_abort(usbd_xfer_handle xfer)
 {
-#ifdef DIAGNOSTIC
-	struct motg_softc *sc = xfer->pipe->device->bus->hci_private;
-#endif
-	struct motg_pipe *otgpipe = (struct motg_pipe *)xfer->pipe;
-	KASSERT(mutex_owned(&sc->sc_lock));
-
 	DPRINTFN(MD_CTRL, ("motg_device_ctrl_abort:\n"));
-	if (otgpipe->hw_ep->xfer == xfer)
-		otgpipe->hw_ep->xfer = NULL;
-	xfer->status = USBD_CANCELLED;
-	usb_transfer_complete(xfer);
+	motg_device_xfer_abort(xfer);
 }
 
 /* Close a device control pipe */
@@ -1890,7 +1892,10 @@
 
 	/* Insert last in queue. */
 	mutex_enter(&sc->sc_lock);
+	DPRINTF(("motg_device_data_transfer(%p) status %d\n",
+	    xfer, xfer->status));
 	err = usb_insert_transfer(xfer);
+	xfer->status = USBD_NOT_STARTED;
 	mutex_exit(&sc->sc_lock);
 	if (err)
 		return (err);
@@ -1909,6 +1914,8 @@
 	struct motg_pipe *otgpipe = (struct motg_pipe *)xfer->pipe;
 	usbd_status err;
 	mutex_enter(&sc->sc_lock);
+	DPRINTF(("motg_device_data_start(%p) status %d\n",
+	    xfer, xfer->status));
 	err = motg_device_data_start1(sc, otgpipe->hw_ep);
 	mutex_exit(&sc->sc_lock);
 	if (err != USBD_IN_PROGRESS)
@@ -1921,7 +1928,7 @@
 static usbd_status
 motg_device_data_start1(struct motg_softc *sc, struct motg_hw_ep *ep)
 {
-	usbd_xfer_handle xfer;
+	usbd_xfer_handle xfer = NULL;
 	struct motg_pipe *otgpipe;
 	usbd_status err = 0;
 	uint32_t val;
@@ -1940,6 +1947,9 @@
 	/* locate the first pipe with work to do */
 	SIMPLEQ_FOREACH(otgpipe, &ep->ep_pipes, ep_pipe_list) {
 		xfer = SIMPLEQ_FIRST(&otgpipe->pipe.queue);
+		DPRINTFN(MD_BULK,
+		    ("motg_device_data_start1 pipe %p xfer %p status %d\n",
+		    otgpipe, xfer, (xfer != NULL) ? xfer->status : 0));
 		if (xfer != NULL) {
 			/* move this pipe to the end of the list */
 			SIMPLEQ_REMOVE(&ep->ep_pipes, otgpipe,
@@ -1953,7 +1963,7 @@
 		err = USBD_NOT_STARTED;
 		goto end;
 	}
-	KASSERT(xfer != NULL);
+	xfer->status = USBD_IN_PROGRESS;
 	KASSERT(otgpipe == (struct motg_pipe *)xfer->pipe);
 	KASSERT(otgpipe->hw_ep == ep);
 #ifdef DIAGNOSTIC
@@ -2095,6 +2105,7 @@
 	int datalen, max_datalen;
 	char *data;
 	bool got_short;
+	usbd_status new_status = USBD_IN_PROGRESS;
 
 	KASSERT(mutex_owned(&sc->sc_lock));
 	KASSERT(ep->ep_number == epnumber);
@@ -2124,24 +2135,21 @@
 
 		csr &= ~MUSB2_MASK_CSRL_RXNAKTO;
 		UWRITE1(sc, MUSB2_REG_RXCSRL, csr);
-		if (xfer)
-			xfer->status = USBD_TIMEOUT; /* XXX */
+		new_status = USBD_TIMEOUT; /* XXX */
 		goto complete;
 	}
 	if (csr & (MUSB2_MASK_CSRL_RXSTALL | MUSB2_MASK_CSRL_RXERROR)) {
-		if (xfer) {
-			if (csr & MUSB2_MASK_CSRL_RXSTALL) 
-				xfer->status = USBD_STALLED;
-			else
-				xfer->status = USBD_IOERROR;
-		}
+		if (csr & MUSB2_MASK_CSRL_RXSTALL) 
+			new_status = USBD_STALLED;
+		else
+			new_status = USBD_IOERROR;
 		/* clear status */
 		UWRITE1(sc, MUSB2_REG_RXCSRL, 0);
 		goto complete;
 	}
 	KASSERT(csr & MUSB2_MASK_CSRL_RXPKTRDY);
 
-	if (xfer == NULL) {
+	if (xfer == NULL || xfer->status != USBD_IN_PROGRESS) {
 		UWRITE1(sc, MUSB2_REG_RXCSRL, 0);
 		goto complete;
 	}
@@ -2158,7 +2166,7 @@
 	    UE_GET_SIZE(UGETW(xfer->pipe->endpoint->edesc->wMaxPacketSize)),
 	    ep->datalen);
 	if (datalen > max_datalen) {
-		xfer->status = USBD_IOERROR;
+		new_status = USBD_IOERROR;
 		UWRITE1(sc, MUSB2_REG_RXCSRL, 0);
 		goto complete;
 	}
@@ -2192,7 +2200,7 @@
 	KASSERT(ep->phase == DATA_IN);
 	if (got_short || (ep->datalen == 0)) {
 		if (ep->need_short_xfer == 0) {
-			xfer->status = USBD_NORMAL_COMPLETION;
+			new_status = USBD_NORMAL_COMPLETION;
 			goto complete;
 		}
 		ep->need_short_xfer = 0;
@@ -2205,8 +2213,11 @@
 	    (xfer != NULL) ? xfer->status : 0));
 	ep->phase = IDLE;
 	ep->xfer = NULL;
-	if (xfer)
+	if (xfer && xfer->status == USBD_IN_PROGRESS) {
+		KASSERT(new_status != USBD_IN_PROGRESS);
+		xfer->status = new_status;
 		usb_transfer_complete(xfer);
+	}
 	motg_device_data_start1(sc, ep);
 }
 
@@ -2217,6 +2228,7 @@
 	usbd_xfer_handle xfer = ep->xfer;
 	uint8_t csr;
 	struct motg_pipe *otgpipe;
+	usbd_status new_status = USBD_IN_PROGRESS;
 
 	KASSERT(mutex_owned(&sc->sc_lock));
 	KASSERT(ep->ep_number == epnumber);
@@ -2233,34 +2245,35 @@
 
 	if (csr & (MUSB2_MASK_CSRL_TXSTALLED|MUSB2_MASK_CSRL_TXERROR)) {
 		/* command not accepted */
-		if (xfer) {
-			if (csr & MUSB2_MASK_CSRL_TXSTALLED) 
-				xfer->status = USBD_STALLED;
-			else
-				xfer->status = USBD_IOERROR;
-		}
+		if (csr & MUSB2_MASK_CSRL_TXSTALLED) 
+			new_status = USBD_STALLED;
+		else
+			new_status = USBD_IOERROR;
 		/* clear status */
 		UWRITE1(sc, MUSB2_REG_TXCSRL, 0);
 		goto complete;
 	}
 	if (csr & MUSB2_MASK_CSRL_TXNAKTO) {
-		if (xfer)
-			xfer->status = USBD_TIMEOUT; /* XXX */
+		new_status = USBD_TIMEOUT; /* XXX */
+		csr &= ~MUSB2_MASK_CSRL_TXNAKTO;
+		UWRITE1(sc, MUSB2_REG_TXCSRL, csr);
 		/* flush fifo */
 		while (csr & MUSB2_MASK_CSRL_TXFIFONEMPTY) {
 			csr |= MUSB2_MASK_CSRL_TXFFLUSH;
+			csr &= ~MUSB2_MASK_CSRL_TXNAKTO;
 			UWRITE1(sc, MUSB2_REG_TXCSRL, csr);
+			delay(1000);
 			csr = UREAD1(sc, MUSB2_REG_TXCSRL);
+			DPRINTFN(MD_BULK, ("TX fifo flush ep %d CSR 0x%x\n",
+			    epnumber, csr));
 		}
-		csr &= ~MUSB2_MASK_CSR0L_NAKTIMO;
-		UWRITE1(sc, MUSB2_REG_TXCSRL, csr);
 		goto complete;
 	}
 	if (csr & (MUSB2_MASK_CSRL_TXFIFONEMPTY|MUSB2_MASK_CSRL_TXPKTRDY)) {
 		/* data still not sent */
 		return;
 	}
-	if (xfer == NULL)
+	if (xfer == NULL || xfer->status != USBD_IN_PROGRESS)
 		goto complete;
 #ifdef DIAGNOSTIC
 	if (ep->phase != DATA_OUT)
@@ -2275,7 +2288,7 @@
 			ep->need_short_xfer = 0;
 			/* one more data phase */
 		} else {
-			xfer->status = USBD_NORMAL_COMPLETION;
+			new_status = USBD_NORMAL_COMPLETION;
 			goto complete;
 		}
 	}
@@ -2287,13 +2300,16 @@
 	    ("motg_device_intr_tx xfer %p complete, status %d\n", xfer,
 	    (xfer != NULL) ? xfer->status : 0));
 #ifdef DIAGNOSTIC
-	if (xfer && ep->phase != DATA_OUT)
+	if (xfer && xfer->status == USBD_IN_PROGRESS && ep->phase != DATA_OUT)
 		panic("motg_device_intr_tx: bad phase %d", ep->phase);
 #endif
 	ep->phase = IDLE;
 	ep->xfer = NULL;
-	if (xfer)
+	if (xfer && xfer->status == USBD_IN_PROGRESS) {
+		KASSERT(new_status != USBD_IN_PROGRESS);
+		xfer->status = new_status;
 		usb_transfer_complete(xfer);
+	}
 	motg_device_data_start1(sc, ep);
 }
 
@@ -2304,39 +2320,10 @@
 #ifdef DIAGNOSTIC
 	struct motg_softc *sc = xfer->pipe->device->bus->hci_private;
 #endif
-	struct motg_pipe *otgpipe = (struct motg_pipe *)xfer->pipe;
-	uint8_t csr;
-
 	KASSERT(mutex_owned(&sc->sc_lock));
 
-	DPRINTFN(MD_BULK, 
-	    ("motg_device_data_abort:\n"));
-	if (otgpipe->hw_ep->xfer == xfer) {
-		otgpipe->hw_ep->xfer = NULL;
-		/* select endpoint */       
-		UWRITE1(sc, MUSB2_REG_EPINDEX, otgpipe->hw_ep->ep_number);
-		if (otgpipe->hw_ep->phase == DATA_OUT) {
-			csr = UREAD1(sc, MUSB2_REG_TXCSRL);
-			while (csr & MUSB2_MASK_CSRL_TXFIFONEMPTY) {
-				csr |= MUSB2_MASK_CSRL_TXFFLUSH;
-				UWRITE1(sc, MUSB2_REG_TXCSRL, csr);
-				csr = UREAD1(sc, MUSB2_REG_TXCSRL);
-			}
-			UWRITE1(sc, MUSB2_REG_TXCSRL, 0);
-		} else if (otgpipe->hw_ep->phase == DATA_IN) {
-			csr = UREAD1(sc, MUSB2_REG_RXCSRL);
-			while (csr & MUSB2_MASK_CSRL_RXPKTRDY) {
-				csr |= MUSB2_MASK_CSRL_RXFFLUSH;
-				UWRITE1(sc, MUSB2_REG_RXCSRL, csr);
-				csr = UREAD1(sc, MUSB2_REG_RXCSRL);
-			}
-			UWRITE1(sc, MUSB2_REG_RXCSRL, 0);
-		}
-		otgpipe->hw_ep->phase = IDLE;
-	}
-
-	xfer->status = USBD_CANCELLED;
-	usb_transfer_complete(xfer);
+	DPRINTFN(MD_BULK, ("motg_device_data_abort:\n"));
+	motg_device_xfer_abort(xfer);
 }
 
 /* Close a device control pipe */
@@ -2389,7 +2376,6 @@
 
 	DPRINTF(("motg_waitintr: timeout = %dms\n", timo));
 
-	xfer->status = USBD_IN_PROGRESS;
 	for (; timo >= 0; timo--) {
 		mutex_exit(&sc->sc_lock);
 		usb_delay_ms(&sc->sc_bus, 1);
@@ -2416,3 +2402,59 @@
 	struct motg_pipe *otgpipe = (struct motg_pipe *)pipe;
 	otgpipe->nexttoggle = 0;
 }
+
+/* Abort a device control request. */
+static void
+motg_device_xfer_abort(usbd_xfer_handle xfer)
+{
+	int wake;
+	uint8_t csr;
+#ifdef DIAGNOSTIC
+	struct motg_softc *sc = xfer->pipe->device->bus->hci_private;
+#endif
+	struct motg_pipe *otgpipe = (struct motg_pipe *)xfer->pipe;
+	KASSERT(mutex_owned(&sc->sc_lock));
+
+	DPRINTF(("motg_device_xfer_abort:\n"));
+	if (xfer->hcflags & UXFER_ABORTING) {
+		DPRINTF(("motg_device_xfer_abort: already aborting\n"));
+		xfer->hcflags |= UXFER_ABORTWAIT;
+		while (xfer->hcflags & UXFER_ABORTING)
+		cv_wait(&xfer->hccv, &sc->sc_lock);
+		return;
+	}
+	xfer->hcflags |= UXFER_ABORTING;
+	if (otgpipe->hw_ep->xfer == xfer) {
+		KASSERT(xfer->status == USBD_IN_PROGRESS);
+		otgpipe->hw_ep->xfer = NULL;
+		if (otgpipe->hw_ep->ep_number > 0) {
+			/* select endpoint */       
+			UWRITE1(sc, MUSB2_REG_EPINDEX,
+			    otgpipe->hw_ep->ep_number);
+			if (otgpipe->hw_ep->phase == DATA_OUT) {
+				csr = UREAD1(sc, MUSB2_REG_TXCSRL);
+				while (csr & MUSB2_MASK_CSRL_TXFIFONEMPTY) {
+					csr |= MUSB2_MASK_CSRL_TXFFLUSH;
+					UWRITE1(sc, MUSB2_REG_TXCSRL, csr);
+					csr = UREAD1(sc, MUSB2_REG_TXCSRL);
+				}
+				UWRITE1(sc, MUSB2_REG_TXCSRL, 0);
+			} else if (otgpipe->hw_ep->phase == DATA_IN) {
+				csr = UREAD1(sc, MUSB2_REG_RXCSRL);
+				while (csr & MUSB2_MASK_CSRL_RXPKTRDY) {
+					csr |= MUSB2_MASK_CSRL_RXFFLUSH;
+					UWRITE1(sc, MUSB2_REG_RXCSRL, csr);
+					csr = UREAD1(sc, MUSB2_REG_RXCSRL);
+				}
+				UWRITE1(sc, MUSB2_REG_RXCSRL, 0);
+			}
+			otgpipe->hw_ep->phase = IDLE;
+		}
+	}
+	xfer->status = USBD_CANCELLED; /* make software ignore it */
+	wake = xfer->hcflags & UXFER_ABORTWAIT;
+	xfer->hcflags &= ~(UXFER_ABORTING | UXFER_ABORTWAIT);
+	usb_transfer_complete(xfer);
+	if (wake)
+		cv_broadcast(&xfer->hccv);
+}