Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 12 Sep 2012 07:34:09 +0000 (UTC)
From:      Hans Petter Selasky <hselasky@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r240381 - head/sys/dev/usb/controller
Message-ID:  <201209120734.q8C7Y9bY020438@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: hselasky
Date: Wed Sep 12 07:34:09 2012
New Revision: 240381
URL: http://svn.freebsd.org/changeset/base/240381

Log:
  Reduce DWC OTG polling rate by using the SOF interrupt.

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	Wed Sep 12 04:29:11 2012	(r240380)
+++ head/sys/dev/usb/controller/dwc_otg.c	Wed Sep 12 07:34:09 2012	(r240381)
@@ -160,6 +160,23 @@ dwc_otg_get_hw_ep_profile(struct usb_dev
 		*ppf = NULL;
 }
 
+static void
+dwc_otg_request_sof(struct dwc_otg_softc *sc)
+{
+	sc->sc_sof_refs++;
+	sc->sc_irq_mask |= GINTMSK_SOFMSK;
+	DWC_OTG_WRITE_4(sc, DOTG_GINTMSK, sc->sc_irq_mask);
+}
+
+static void
+dwc_otg_release_sof(struct dwc_otg_softc *sc)
+{
+	if (--(sc->sc_sof_refs) == 0) {
+		sc->sc_irq_mask &= ~GINTMSK_SOFMSK;
+		DWC_OTG_WRITE_4(sc, DOTG_GINTMSK, sc->sc_irq_mask);
+	}
+}
+
 static int
 dwc_otg_init_fifo(struct dwc_otg_softc *sc, uint8_t mode)
 {
@@ -523,6 +540,9 @@ dwc_otg_host_channel_alloc(struct dwc_ot
 			/* set active EP */
 			sc->sc_active_rx_ep |= (1 << x);
 
+			/* request SOF's */
+			dwc_otg_request_sof(sc);
+
 			return (0);	/* allocated */
 		}
 	}
@@ -576,6 +596,10 @@ dwc_otg_host_setup_tx(struct dwc_otg_td 
 			td->remainder -= td->tx_bytes;
 			td->toggle = 1;
 			return (0);	/* complete */
+		} else {
+			if ((sc->sc_sof_val & 1) != (td->sof_val & 1))
+				return (1);	/* busy */
+			td->sof_val += 1;
 		}
 	} else {
 		return (1);	/* busy */
@@ -882,12 +906,19 @@ not_complete:
 		/* DATA 0 */
 		td->toggle = 0;
 	} else if (ep_type == UE_INTERRUPT) {
-		if ((sc->sc_interrupt_val & 0xFF) != td->sof_val)
+		if ((sc->sc_sof_val & 0xFF) != td->sof_val)
 			return (1);	/* busy */
 		td->sof_val += td->sof_res;
-	} else if (td->set_toggle) {
-		td->set_toggle = 0;
-		td->toggle = 1;
+	} else {
+		if (td->did_nak) {
+			if ((sc->sc_sof_val & 1) != (td->sof_val & 1))
+				return (1);	/* busy */
+			td->sof_val += 1;
+		}
+		if (td->set_toggle) {
+			td->set_toggle = 0;
+			td->toggle = 1;
+		}
 	}
 
 	/* receive one packet */
@@ -1078,7 +1109,11 @@ dwc_otg_host_data_tx(struct dwc_otg_td *
 
 				/* else we need to transmit a short packet */
 			}
-		}
+		} else {
+			if ((sc->sc_sof_val & 1) != (td->sof_val & 1))
+				return (1);	/* busy */
+			td->sof_val += 1;
+ 		}
 	} else {
 		return (1);	/* busy */
 	}
@@ -1098,7 +1133,7 @@ dwc_otg_host_data_tx(struct dwc_otg_td *
 		td->toggle = 0;
 
 	} else if (ep_type == UE_INTERRUPT) {
-		if ((sc->sc_interrupt_val & 0xFF) != td->sof_val)
+		if ((sc->sc_sof_val & 0xFF) != td->sof_val)
 			return (1);	/* busy */
 		td->sof_val += td->sof_res;
 	} else if (td->set_toggle) {
@@ -1775,21 +1810,8 @@ dwc_otg_interrupt(struct dwc_otg_softc *
 	}
 
 	/* check for Start Of Frame IRQ */
-	if (status & GINTMSK_SOFMSK) {
-
-		uint32_t temp;
-
-		temp = DWC_OTG_READ_4(sc, DOTG_HFNUM);
-		temp &= HFNUM_FRNUM_MASK;
-
-		if (sc->sc_flags.status_high_speed) {
-			if ((temp & 7) == (sc->sc_sof_val & 7))
-				sc->sc_sof_val++;
-		} else {
-			if ((temp & 1) == (sc->sc_sof_val & 1))
-				sc->sc_sof_val++;
-		}
-	}
+	if (status & GINTMSK_SOFMSK)
+		sc->sc_sof_val++;
 
 	/* poll FIFO(s) */
 	dwc_otg_interrupt_poll(sc);
@@ -2058,6 +2080,16 @@ dwc_otg_setup_standard_chain(struct usb_
 			} else {
 				td->hcsplt = 0;
 			}
+			if (xfer_type == UE_INTERRUPT) {
+				uint32_t ival;
+				ival = xfer->interval;
+				if (ival == 0)
+					ival = 1;
+				else if (ival > 255)
+					ival = 255;
+				td->sof_val = sc->sc_sof_val + ival;
+				td->sof_res = ival;
+			}
 			break;
 		case USB_SPEED_HIGH:
 			td->hcsplt = 0;
@@ -2066,6 +2098,16 @@ dwc_otg_setup_standard_chain(struct usb_
 				td->hcchar |= ((xfer->max_packet_count & 3)
 				    << HCCHAR_MC_SHIFT);
 			}
+			if (xfer_type == UE_INTERRUPT) {
+				uint32_t ival;
+				ival = xfer->interval * 8;
+				if (ival == 0)
+					ival = 1;
+				else if (ival > 255)
+					ival = 255;
+				td->sof_val = sc->sc_sof_val + ival;
+				td->sof_res = ival;
+			}
 			break;
 		default:
 			td->hcsplt = 0;
@@ -2075,9 +2117,9 @@ dwc_otg_setup_standard_chain(struct usb_
 		if (xfer_type == UE_ISOCHRONOUS) {
 			td->sof_val = xfer->endpoint->isoc_next & 0xFF;
 			td->sof_res = 1 << usbd_xfer_get_fps_shift(xfer);
-		} else if (xfer_type == UE_INTERRUPT) {
-			td->sof_val = sc->sc_interrupt_val;
-			td->sof_res = 0;	/* TODO */
+		} else if (xfer_type != UE_INTERRUPT) {
+			td->sof_val = sc->sc_sof_val + 1;
+			td->sof_res = 1;
 		}
 	}
 }
@@ -2269,6 +2311,9 @@ dwc_otg_device_done(struct usb_xfer *xfe
 			sc->sc_active_rx_ep &= ~(1 << td->channel);
 
 			td->channel = DWC_OTG_MAX_CHANNELS;
+
+			/* release SOF's */
+			dwc_otg_release_sof(sc);
 		}
 	}
 	/* dequeue transfer and start next transfer */
@@ -2742,32 +2787,22 @@ struct usb_pipe_methods dwc_otg_device_n
 static void
 dwc_otg_device_isoc_open(struct usb_xfer *xfer)
 {
-	struct dwc_otg_softc *sc = DWC_OTG_BUS2SC(xfer->xroot->bus);
-
 	if (xfer->xroot->udev->flags.usb_mode == USB_MODE_HOST) {
-		xfer->qh_pos = 1;
-		sc->sc_sof_refs++;
-		sc->sc_irq_mask |= GINTMSK_SOFMSK;
-		DWC_OTG_WRITE_4(sc, DOTG_GINTMSK, sc->sc_irq_mask);
+		struct dwc_otg_softc *sc = DWC_OTG_BUS2SC(xfer->xroot->bus);
 
-		usb_hs_bandwidth_alloc(xfer);
+		xfer->qh_pos = 1;
+		dwc_otg_request_sof(sc);
 	}
 }
 
 static void
 dwc_otg_device_isoc_close(struct usb_xfer *xfer)
 {
-	struct dwc_otg_softc *sc = DWC_OTG_BUS2SC(xfer->xroot->bus);
-
 	if (xfer->qh_pos != 0) {
+		struct dwc_otg_softc *sc = DWC_OTG_BUS2SC(xfer->xroot->bus);
+
 		xfer->qh_pos = 0;
-		if (--(sc->sc_sof_refs) == 0) {
-			sc->sc_irq_mask &= ~GINTMSK_SOFMSK;
-			DWC_OTG_WRITE_4(sc, DOTG_GINTMSK, sc->sc_irq_mask);
-		}
-	}
-	if (xfer->xroot->udev->flags.usb_mode == USB_MODE_HOST) {
-		usb_hs_bandwidth_free(xfer);
+		dwc_otg_release_sof(sc);
 	}
 	dwc_otg_device_done(xfer, USB_ERR_CANCELLED);
 }

Modified: head/sys/dev/usb/controller/dwc_otg.h
==============================================================================
--- head/sys/dev/usb/controller/dwc_otg.h	Wed Sep 12 04:29:11 2012	(r240380)
+++ head/sys/dev/usb/controller/dwc_otg.h	Wed Sep 12 07:34:09 2012	(r240381)
@@ -151,8 +151,6 @@ struct dwc_otg_softc {
 	uint32_t sc_hcchar[DWC_OTG_MAX_CHANNELS];
 	uint32_t sc_sof_refs;
 	uint32_t sc_sof_val;
-	uint32_t sc_interrupt_refs;
-	uint32_t sc_interrupt_val;
 	uint32_t sc_hprt_val;
 
 	uint16_t sc_active_rx_ep;



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201209120734.q8C7Y9bY020438>