svn commit: r265872 - head/sys/dev/usb/controller

Hans Petter Selasky hselasky at FreeBSD.org
Sun May 11 08:17:46 UTC 2014


Author: hselasky
Date: Sun May 11 08:17:46 2014
New Revision: 265872
URL: http://svnweb.freebsd.org/changeset/base/265872

Log:
  Optimise host mode data roundtrip time. When BULK data is submitted to
  the main processing queue, clear the NAK counter for any associated
  BULK or CONTROL transfers and poll the endpoint(s) for 1 millisecond
  at 125us rate interval, before going into slow, 10ms, NAK polling mode
  again.  This has the effect that typical ping-ping protocols respond
  quicker when initiated from the USB host.
  
  MFC after:	2 weeks

Modified:
  head/sys/dev/usb/controller/dwc_otg.c
  head/sys/dev/usb/controller/dwc_otg.h

Modified: head/sys/dev/usb/controller/dwc_otg.c
==============================================================================
--- head/sys/dev/usb/controller/dwc_otg.c	Sun May 11 05:49:35 2014	(r265871)
+++ head/sys/dev/usb/controller/dwc_otg.c	Sun May 11 08:17:46 2014	(r265872)
@@ -760,7 +760,7 @@ check_state:
 
 	case DWC_CHAN_ST_WAIT_ANE:
 		if (hcint & (HCINT_RETRY | HCINT_ERRORS)) {
-			td->did_nak = 1;
+			td->did_nak++;
 			td->tt_scheduled = 0;
 			goto send_pkt;
 		} else if (hcint & (HCINT_ACK | HCINT_NYET)) {
@@ -774,7 +774,7 @@ check_state:
 
 	case DWC_CHAN_ST_WAIT_S_ANE:
 		if (hcint & (HCINT_RETRY | HCINT_ERRORS)) {
-			td->did_nak = 1;
+			td->did_nak++;
 			td->tt_scheduled = 0;
 			goto send_pkt;
 		} else if (hcint & (HCINT_ACK | HCINT_NYET)) {
@@ -786,7 +786,7 @@ check_state:
 		if (hcint & HCINT_NYET) {
 			goto send_cpkt;
 		} else if (hcint & (HCINT_RETRY | HCINT_ERRORS)) {
-			td->did_nak = 1;
+			td->did_nak++;
 			td->tt_scheduled = 0;
 			goto send_pkt;
 		} else if (hcint & HCINT_ACK) {
@@ -1085,7 +1085,7 @@ dwc_otg_host_rate_check(struct dwc_otg_t
 		if (!td->tt_scheduled)
 			goto busy;
 		td->tt_scheduled = 0;
-	} else if (td->did_nak != 0) {
+	} else if (td->did_nak >= DWC_OTG_NAK_MAX) {
 		goto busy;
 	} else if (td->set_toggle) {
 		td->set_toggle = 0;
@@ -1244,7 +1244,7 @@ check_state:
 
 	case DWC_CHAN_ST_WAIT_ANE:
 		if (hcint & (HCINT_RETRY | HCINT_ERRORS)) {
-			td->did_nak = 1;
+			td->did_nak++;
 			td->tt_scheduled = 0;
 			if (td->hcsplt != 0)
 				goto receive_spkt;
@@ -1284,6 +1284,7 @@ check_state:
 					 */
 				}
 				td->tt_scheduled = 0;
+				td->did_nak = 0;
 				if (td->hcsplt != 0)
 					goto receive_spkt;
 				else
@@ -1298,14 +1299,16 @@ check_state:
 		 * case of interrupt and isochronous transfers:
 		 */ 
 		if (hcint & (HCINT_RETRY | HCINT_ERRORS)) {
-			td->did_nak = 1;
+			td->did_nak++;
 			td->tt_scheduled = 0;
 			goto receive_spkt;
 		} else if (hcint & HCINT_NYET) {
 			td->tt_scheduled = 0;
 			goto receive_spkt;
-		} else if (hcint & HCINT_ACK)
+		} else if (hcint & HCINT_ACK) {
+			td->did_nak = 0;
 			goto receive_pkt;
+		}
 		break;
 
 	case DWC_CHAN_ST_WAIT_C_PKT:
@@ -1633,13 +1636,14 @@ check_state:
 
 	case DWC_CHAN_ST_WAIT_ANE:
 		if (hcint & (HCINT_RETRY | HCINT_ERRORS)) {
-			td->did_nak = 1;
+			td->did_nak++;
 			td->tt_scheduled = 0;
 			goto send_pkt;
 		} else if (hcint & (HCINT_ACK | HCINT_NYET)) {
 			td->offset += td->tx_bytes;
 			td->remainder -= td->tx_bytes;
 			td->toggle ^= 1;
+			td->did_nak = 0;
 			td->tt_scheduled = 0;
 
 			/* check remainder */
@@ -1658,24 +1662,27 @@ check_state:
 
 	case DWC_CHAN_ST_WAIT_S_ANE:
 		if (hcint & (HCINT_RETRY | HCINT_ERRORS)) {
-			td->did_nak = 1;
+			td->did_nak++;
 			td->tt_scheduled = 0;
 			goto send_pkt;
-		} else if (hcint & (HCINT_ACK | HCINT_NYET))
+		} else if (hcint & (HCINT_ACK | HCINT_NYET)) {
+			td->did_nak = 0;
 			goto send_cpkt;
+		}
 		break;
 
 	case DWC_CHAN_ST_WAIT_C_ANE:
 		if (hcint & HCINT_NYET) {
 			goto send_cpkt;
 		} else if (hcint & (HCINT_RETRY | HCINT_ERRORS)) {
-			td->did_nak = 1;
+			td->did_nak++;
 			td->tt_scheduled = 0;
 			goto send_pkt;
 		} else if (hcint & HCINT_ACK) {
 			td->offset += td->tx_bytes;
 			td->remainder -= td->tx_bytes;
 			td->toggle ^= 1;
+			td->did_nak = 0;
 			td->tt_scheduled = 0;
 
 			/* check remainder */
@@ -2283,8 +2290,10 @@ dwc_otg_timer(void *_sc)
 
 	TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) {
 		td = xfer->td_transfer_cache;
-		if (td != NULL)
+		if (td != NULL) {
+			/* reset NAK counter */ 
 			td->did_nak = 0;
+		}
 	}
 
 	/* enable SOF interrupt, which will poll jobs */
@@ -2429,8 +2438,11 @@ dwc_otg_update_host_transfer_schedule(st
 
 		TAILQ_FOREACH_SAFE(xfer, &sc->sc_bus.intr_q.head, wait_entry, xfer_next) {
 			td = xfer->td_transfer_cache;
-			if (td == NULL || td->did_nak != 0 || td->ep_type != UE_CONTROL)
+			if (td == NULL ||
+			    td->ep_type != UE_CONTROL ||
+			    td->did_nak >= DWC_OTG_NAK_MAX) {
 				continue;
+			}
 
 			sc->sc_needsof = 1;
 
@@ -2448,8 +2460,11 @@ dwc_otg_update_host_transfer_schedule(st
 	if ((temp & 7) < 6) {
 		TAILQ_FOREACH_SAFE(xfer, &sc->sc_bus.intr_q.head, wait_entry, xfer_next) {
 			td = xfer->td_transfer_cache;
-			if (td == NULL || td->did_nak != 0 || td->ep_type != UE_BULK)
+			if (td == NULL ||
+			    td->ep_type != UE_BULK ||
+			    td->did_nak >= DWC_OTG_NAK_MAX) {
 				continue;
+			}
 
 			sc->sc_needsof = 1;
 
@@ -3206,24 +3221,53 @@ static void
 dwc_otg_start_standard_chain(struct usb_xfer *xfer)
 {
 	struct dwc_otg_softc *sc = DWC_OTG_BUS2SC(xfer->xroot->bus);
+	struct usb_xfer_root *xroot;
+	struct dwc_otg_td *td;
 
 	DPRINTFN(9, "\n");
 
-	/* poll one time - will turn on interrupts */
-	if (dwc_otg_xfer_do_fifo(xfer)) {
+	/*
+	 * Poll one time in device mode, which will turn on the
+	 * endpoint interrupts. Else wait for SOF interrupt in host
+	 * mode.
+	 */
+	if (sc->sc_flags.status_device_mode != 0 &&
+	    dwc_otg_xfer_do_fifo(xfer) == 0)
+		goto done;
 
-		/* put transfer on interrupt queue */
-		usbd_transfer_enqueue(&xfer->xroot->bus->intr_q, xfer);
+	/* put transfer on interrupt queue */
+	usbd_transfer_enqueue(&xfer->xroot->bus->intr_q, xfer);
 
-		/* start timeout, if any */
-		if (xfer->timeout != 0) {
-			usbd_transfer_timeout_ms(xfer,
-			    &dwc_otg_timeout, xfer->timeout);
-		}
+	/* start timeout, if any */
+	if (xfer->timeout != 0) {
+		usbd_transfer_timeout_ms(xfer,
+		    &dwc_otg_timeout, xfer->timeout);
+	}
+
+	if (sc->sc_flags.status_device_mode != 0)
+		goto done;
 
-		/* enable SOF interrupt, if any */
-		dwc_otg_enable_sof_irq(sc);
+	/* enable SOF interrupt, if any */
+	dwc_otg_enable_sof_irq(sc);
+
+	td = xfer->td_transfer_cache;
+	if (td->ep_type != UE_BULK)
+		goto done;
+
+	xroot = xfer->xroot;
+
+	/*
+	 * Optimise the ping-pong effect by waking up other BULK
+	 * transfers belonging to the same device group:
+	 */
+	TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) {
+		td = xfer->td_transfer_cache;
+		if (td == NULL || td->ep_type != UE_BULK || xfer->xroot != xroot)
+			continue;
+		/* reset NAK counter */ 
+		td->did_nak = 0;
 	}
+done:;
 }
 
 static void

Modified: head/sys/dev/usb/controller/dwc_otg.h
==============================================================================
--- head/sys/dev/usb/controller/dwc_otg.h	Sun May 11 05:49:35 2014	(r265871)
+++ head/sys/dev/usb/controller/dwc_otg.h	Sun May 11 08:17:46 2014	(r265872)
@@ -37,6 +37,7 @@
 #define	DWC_OTG_TT_SLOT_MAX 8
 #define	DWC_OTG_SLOT_IDLE_MAX 4
 #define	DWC_OTG_SLOT_IDLE_MIN 2
+#define	DWC_OTG_NAK_MAX 8	/* 1 ms */
 
 #define	DWC_OTG_READ_4(sc, reg) \
   bus_space_read_4((sc)->sc_io_tag, (sc)->sc_io_hdl, reg)
@@ -64,6 +65,7 @@ struct dwc_otg_td {
 	uint8_t errcnt;
 	uint8_t tmr_res;
 	uint8_t tmr_val;
+	uint8_t did_nak;		/* NAK counter */
 	uint8_t	ep_no;
 	uint8_t ep_type;
 	uint8_t channel[2];
@@ -87,7 +89,6 @@ struct dwc_otg_td {
 	uint8_t toggle:1;
 	uint8_t set_toggle:1;
 	uint8_t got_short:1;
-	uint8_t did_nak:1;
 	uint8_t tt_scheduled:1;
 	uint8_t tt_channel_tog:1;
 };


More information about the svn-src-all mailing list