Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 8 Nov 2015 09:37:27 +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: r290542 - head/sys/dev/usb/controller
Message-ID:  <201511080937.tA89bRlZ002561@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: hselasky
Date: Sun Nov  8 09:37:26 2015
New Revision: 290542
URL: https://svnweb.freebsd.org/changeset/base/290542

Log:
  Avoid using the bounce buffer when the source or destination buffer is
  32-bits aligned. Merge the two bounce buffers into a single one. Some
  rough tests showed that the DWC OTG throughput on RPI2 increased by
  10% after this patch.
  
  MFC after:	1 week

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 Nov  8 08:31:34 2015	(r290541)
+++ head/sys/dev/usb/controller/dwc_otg.c	Sun Nov  8 09:37:26 2015	(r290542)
@@ -181,6 +181,110 @@ dwc_otg_get_hw_ep_profile(struct usb_dev
 }
 
 static void
+dwc_otg_write_fifo(struct dwc_otg_softc *sc, struct usb_page_cache *pc,
+    uint32_t offset, uint32_t fifo, uint32_t count)
+{
+	uint32_t temp;
+
+	/* round down length to nearest 4-bytes */
+	temp = count & ~3;
+
+	/* check if we can write the data directly */
+	if (temp != 0 && usb_pc_buffer_is_aligned(pc, offset, temp, 3)) {
+		struct usb_page_search buf_res;
+
+		/* pre-subtract length */
+		count -= temp;
+
+		/* iterate buffer list */
+		do {
+			/* get current buffer pointer */
+			usbd_get_page(pc, offset, &buf_res);
+
+			if (buf_res.length > temp)
+				buf_res.length = temp;
+
+			/* transfer data into FIFO */
+			bus_space_write_region_4(sc->sc_io_tag, sc->sc_io_hdl,
+			    fifo, buf_res.buffer, buf_res.length / 4);
+
+			offset += buf_res.length;
+			fifo += buf_res.length;
+			temp -= buf_res.length;
+		} while (temp != 0);
+	}
+
+	/* check for remainder */
+	if (count != 0) {
+		/* clear topmost word before copy */
+		sc->sc_bounce_buffer[(count - 1) / 4] = 0;
+
+		/* copy out data */
+		usbd_copy_out(pc, offset,
+		    sc->sc_bounce_buffer, count);
+
+		/* transfer data into FIFO */
+		bus_space_write_region_4(sc->sc_io_tag,
+		    sc->sc_io_hdl, fifo, sc->sc_bounce_buffer,
+		    (count + 3) / 4);
+	}
+}
+
+static void
+dwc_otg_read_fifo(struct dwc_otg_softc *sc, struct usb_page_cache *pc,
+    uint32_t offset, uint32_t count)
+{
+	uint32_t temp;
+
+	/* round down length to nearest 4-bytes */
+	temp = count & ~3;
+
+	/* check if we can read the data directly */
+	if (temp != 0 && usb_pc_buffer_is_aligned(pc, offset, temp, 3)) {
+		struct usb_page_search buf_res;
+
+		/* pre-subtract length */
+		count -= temp;
+
+		/* iterate buffer list */
+		do {
+			/* get current buffer pointer */
+			usbd_get_page(pc, offset, &buf_res);
+
+			if (buf_res.length > temp)
+				buf_res.length = temp;
+
+			/* transfer data from FIFO */
+			bus_space_read_region_4(sc->sc_io_tag, sc->sc_io_hdl,
+			    sc->sc_current_rx_fifo, buf_res.buffer, buf_res.length / 4);
+
+			offset += buf_res.length;
+			sc->sc_current_rx_fifo += buf_res.length;
+			sc->sc_current_rx_bytes -= buf_res.length;
+			temp -= buf_res.length;
+		} while (temp != 0);
+	}
+
+	/* check for remainder */
+	if (count != 0) {
+		/* read data into bounce buffer */
+		bus_space_read_region_4(sc->sc_io_tag, sc->sc_io_hdl,
+			sc->sc_current_rx_fifo,
+			sc->sc_bounce_buffer, (count + 3) / 4);
+
+		/* store data into proper buffer */
+		usbd_copy_in(pc, offset, sc->sc_bounce_buffer, count);
+
+		/* round length up to nearest 4 bytes */
+		count = (count + 3) & ~3;
+
+		/* update counters */
+		sc->sc_current_rx_bytes -= count;
+		sc->sc_current_rx_fifo += count;
+	}
+}
+
+static void
 dwc_otg_tx_fifo_reset(struct dwc_otg_softc *sc, uint32_t value)
 {
 	uint32_t temp;
@@ -579,6 +683,14 @@ dwc_otg_common_rx_ack(struct dwc_otg_sof
 	sc->sc_irq_mask |= GINTMSK_RXFLVLMSK;
 	DWC_OTG_WRITE_4(sc, DOTG_GINTMSK, sc->sc_irq_mask);
 
+	if (sc->sc_current_rx_bytes != 0) {
+		/* need to dump remaining data */
+		bus_space_read_region_4(sc->sc_io_tag, sc->sc_io_hdl,
+		    sc->sc_current_rx_fifo, sc->sc_bounce_buffer,
+		    sc->sc_current_rx_bytes / 4);
+		/* clear number of active bytes to receive */
+		sc->sc_current_rx_bytes = 0;
+	}
 	/* clear cached status */
 	sc->sc_last_rx_status = 0;
 }
@@ -761,6 +873,7 @@ dwc_otg_host_dump_rx(struct dwc_otg_soft
 		    td->channel[x] != GRXSTSRD_CHNUM_GET(sc->sc_last_rx_status))
 			continue;
 		dwc_otg_common_rx_ack(sc);
+		break;
 	}
 }
 
@@ -898,6 +1011,7 @@ send_pkt:
 		td->state = DWC_CHAN_ST_WAIT_ANE;
 	}
 
+	/* copy out control request */
 	usbd_copy_out(td->pc, 0, &req, sizeof(req));
 
 	DWC_OTG_WRITE_4(sc, DOTG_HCTSIZ(td->channel[0]),
@@ -1024,11 +1138,11 @@ dwc_otg_setup_rx(struct dwc_otg_softc *s
 		goto not_complete;
 	}
 
-	/* copy in control request */
-	memcpy(&req, sc->sc_rx_bounce_buffer, sizeof(req));
+	/* read FIFO */
+	dwc_otg_read_fifo(sc, td->pc, 0, sizeof(req));
 
-	/* copy data into real buffer */
-	usbd_copy_in(td->pc, 0, &req, sizeof(req));
+	/* copy out control request */
+	usbd_copy_out(td->pc, 0, &req, sizeof(req));
 
 	td->offset = sizeof(req);
 	td->remainder = 0;
@@ -1212,8 +1326,8 @@ dwc_otg_host_data_rx_sub(struct dwc_otg_
 			goto complete;
 		}
 
-		usbd_copy_in(td->pc, td->offset,
-		    sc->sc_rx_bounce_buffer, count);
+		/* read data from FIFO */
+		dwc_otg_read_fifo(sc, td->pc, td->offset, count);
 
 		td->remainder -= count;
 		td->offset += count;
@@ -1583,7 +1697,9 @@ dwc_otg_data_rx(struct dwc_otg_softc *sc
 		return (0);		/* we are complete */
 	}
 
-	usbd_copy_in(td->pc, td->offset, sc->sc_rx_bounce_buffer, count);
+	/* read data from FIFO */
+	dwc_otg_read_fifo(sc, td->pc, td->offset, count);
+
 	td->remainder -= count;
 	td->offset += count;
 
@@ -1904,17 +2020,9 @@ send_pkt:
 		DWC_OTG_WRITE_4(sc, DOTG_HCCHAR(channel), hcchar);
 
 		if (count != 0) {
-			/* clear topmost word before copy */
-			sc->sc_tx_bounce_buffer[(count - 1) / 4] = 0;
-
-			/* copy out data */
-			usbd_copy_out(td->pc, td->offset + td->tx_bytes,
-			    sc->sc_tx_bounce_buffer, count);
-
-			/* transfer data into FIFO */
-			bus_space_write_region_4(sc->sc_io_tag, sc->sc_io_hdl,
-			    DOTG_DFIFO(channel),
-			    sc->sc_tx_bounce_buffer, (count + 3) / 4);
+			/* write data into FIFO */
+			dwc_otg_write_fifo(sc, td->pc, td->offset +
+			    td->tx_bytes, DOTG_DFIFO(channel), count);
 		}
 
 		/* store number of bytes transmitted */
@@ -2054,18 +2162,9 @@ repeat:
 			count = fifo_left;
 
 		if (count != 0) {
-
-			/* clear topmost word before copy */
-			sc->sc_tx_bounce_buffer[(count - 1) / 4] = 0;
-
-			/* copy out data */
-			usbd_copy_out(td->pc, td->offset,
-			    sc->sc_tx_bounce_buffer, count);
-
-			/* transfer data into FIFO */
-			bus_space_write_region_4(sc->sc_io_tag, sc->sc_io_hdl,
-			    DOTG_DFIFO(td->ep_no),
-			    sc->sc_tx_bounce_buffer, (count + 3) / 4);
+			/* write data into FIFO */
+			dwc_otg_write_fifo(sc, td->pc, td->offset,
+			    DOTG_DFIFO(td->ep_no), count);
 
 			td->tx_bytes -= count;
 			td->remainder -= count;
@@ -2616,6 +2715,11 @@ repeat:
 					sc->sc_chan_state[ep_no].wait_halted = 0;
 					DPRINTFN(5, "channel halt complete ch=%u\n", ep_no);
 				}
+				/* store bytes and FIFO offset */
+				sc->sc_current_rx_bytes = 0;
+				sc->sc_current_rx_fifo = 0;
+
+				/* acknowledge status */
 				dwc_otg_common_rx_ack(sc);
 				goto repeat;
 			}
@@ -2625,13 +2729,11 @@ repeat:
 			ep_no = GRXSTSRD_CHNUM_GET(
 			    sc->sc_last_rx_status);
 
-			/* receive data, if any */
-			if (temp != 0) {
-				DPRINTF("Reading %d bytes from ep %d\n", temp, ep_no);
-				bus_space_read_region_4(sc->sc_io_tag, sc->sc_io_hdl,
-				    DOTG_DFIFO(ep_no),
-				    sc->sc_rx_bounce_buffer, (temp + 3) / 4);
-			}
+			/* store bytes and FIFO offset */
+			sc->sc_current_rx_bytes = (temp + 3) & ~3;
+			sc->sc_current_rx_fifo = DOTG_DFIFO(ep_no);
+
+			DPRINTF("Reading %d bytes from ep %d\n", temp, ep_no);
 
 			/* check if we should dump the data */
 			if (!(sc->sc_active_rx_ep & (1U << ep_no))) {

Modified: head/sys/dev/usb/controller/dwc_otg.h
==============================================================================
--- head/sys/dev/usb/controller/dwc_otg.h	Sun Nov  8 08:31:34 2015	(r290541)
+++ head/sys/dev/usb/controller/dwc_otg.h	Sun Nov  8 09:37:26 2015	(r290542)
@@ -173,8 +173,7 @@ struct dwc_otg_softc {
 	bus_space_tag_t sc_io_tag;
 	bus_space_handle_t sc_io_hdl;
 
-	uint32_t sc_rx_bounce_buffer[1024 / 4];
-	uint32_t sc_tx_bounce_buffer[MAX(512 * DWC_OTG_MAX_TXP, 1024) / 4];
+	uint32_t sc_bounce_buffer[MAX(512 * DWC_OTG_MAX_TXP, 1024) / 4];
 
 	uint32_t sc_fifo_size;
 	uint32_t sc_irq_mask;
@@ -186,6 +185,9 @@ struct dwc_otg_softc {
 	uint32_t sc_hprt_val;
 	uint32_t sc_xfer_complete;
 
+	uint16_t sc_current_rx_bytes;
+	uint16_t sc_current_rx_fifo;
+
 	uint16_t sc_active_rx_ep;
 	uint16_t sc_last_frame_num;
 



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