PERFORCE change 149389 for review

Hans Petter Selasky hselasky at FreeBSD.org
Sun Sep 7 20:35:05 UTC 2008


http://perforce.freebsd.org/chv.cgi?CH=149389

Change 149389 by hselasky at hselasky_laptop001 on 2008/09/07 20:34:59

	
	The musbotg hardware does not support inter-mixing 1-byte
	and 4-byte transfers, which means we have to use a bounce
	buffer for unaligned buffers.
	
	Re-factor DRQ API to be more generic.

Affected files ...

.. //depot/projects/usb/src/sys/dev/usb2/controller/musb2_otg.c#11 edit
.. //depot/projects/usb/src/sys/dev/usb2/controller/musb2_otg.h#6 edit
.. //depot/projects/usb/src/sys/dev/usb2/controller/musb2_otg_atmelarm.c#4 edit

Differences ...

==== //depot/projects/usb/src/sys/dev/usb2/controller/musb2_otg.c#11 (text+ko) ====

@@ -431,15 +431,34 @@
 		if (buf_res.length > count) {
 			buf_res.length = count;
 		}
-		/*
-		 * Compute the least number of bytes to the next buffer
-		 * alignment address:
-		 */
-		temp = 4 - (USB_P2U(buf_res.buffer) & 3);
+		/* check for unaligned memory address */
+		if (USB_P2U(buf_res.buffer) & 3) {
+
+			temp = count & ~3;
+
+			if (temp) {
+				/* receive data 4 bytes at a time */
+				bus_space_read_multi_4(sc->sc_io_tag, sc->sc_io_hdl,
+				    MUSB2_REG_EPFIFO(0), sc->sc_bounce_buf,
+				    temp / 4);
+			}
+			temp = count & 3;
+			if (temp) {
+				/* receive data 1 byte at a time */
+				bus_space_read_multi_1(sc->sc_io_tag, sc->sc_io_hdl,
+				    MUSB2_REG_EPFIFO(0),
+				    (void *)(&sc->sc_bounce_buf[count / 4]), temp);
+			}
+			usb2_copy_in(td->pc, td->offset,
+			    sc->sc_bounce_buf, count);
 
+			/* update offset and remainder */
+			td->offset += count;
+			td->remainder -= count;
+			break;
+		}
 		/* check if we can optimise */
-		if ((temp == 4) &&
-		    (buf_res.length >= 4)) {
+		if (buf_res.length >= 4) {
 
 			/* receive data 4 bytes at a time */
 			bus_space_read_multi_4(sc->sc_io_tag, sc->sc_io_hdl,
@@ -454,10 +473,6 @@
 			td->remainder -= temp;
 			continue;
 		}
-		/* minimise data transfer length */
-		if (buf_res.length > temp) {
-			buf_res.length = temp;
-		}
 		/* receive data */
 		bus_space_read_multi_1(sc->sc_io_tag, sc->sc_io_hdl,
 		    MUSB2_REG_EPFIFO(0), buf_res.buffer, buf_res.length);
@@ -534,15 +549,34 @@
 		if (buf_res.length > count) {
 			buf_res.length = count;
 		}
-		/*
-		 * Compute the least number of bytes to the next buffer
-		 * alignment address:
-		 */
-		temp = 4 - (USB_P2U(buf_res.buffer) & 3);
+		/* check for unaligned memory address */
+		if (USB_P2U(buf_res.buffer) & 3) {
+
+			usb2_copy_out(td->pc, td->offset,
+			    sc->sc_bounce_buf, count);
+
+			temp = count & ~3;
 
+			if (temp) {
+				/* transmit data 4 bytes at a time */
+				bus_space_write_multi_4(sc->sc_io_tag, sc->sc_io_hdl,
+				    MUSB2_REG_EPFIFO(0), sc->sc_bounce_buf,
+				    temp / 4);
+			}
+			temp = count & 3;
+			if (temp) {
+				/* receive data 1 byte at a time */
+				bus_space_write_multi_1(sc->sc_io_tag, sc->sc_io_hdl,
+				    MUSB2_REG_EPFIFO(0),
+				    ((void *)&sc->sc_bounce_buf[count / 4]), temp);
+			}
+			/* update offset and remainder */
+			td->offset += count;
+			td->remainder -= count;
+			break;
+		}
 		/* check if we can optimise */
-		if ((temp == 4) &&
-		    (buf_res.length >= 4)) {
+		if (buf_res.length >= 4) {
 
 			/* transmit data 4 bytes at a time */
 			bus_space_write_multi_4(sc->sc_io_tag, sc->sc_io_hdl,
@@ -557,10 +591,6 @@
 			td->remainder -= temp;
 			continue;
 		}
-		/* minimise data transfer length */
-		if (buf_res.length > temp) {
-			buf_res.length = temp;
-		}
 		/* transmit data */
 		bus_space_write_multi_1(sc->sc_io_tag, sc->sc_io_hdl,
 		    MUSB2_REG_EPFIFO(0), buf_res.buffer, buf_res.length);
@@ -734,6 +764,32 @@
 		if (buf_res.length > count) {
 			buf_res.length = count;
 		}
+		/* check for unaligned memory address */
+		if (USB_P2U(buf_res.buffer) & 3) {
+
+			temp = count & ~3;
+
+			if (temp) {
+				/* receive data 4 bytes at a time */
+				bus_space_read_multi_4(sc->sc_io_tag, sc->sc_io_hdl,
+				    MUSB2_REG_EPFIFO(td->ep_no), sc->sc_bounce_buf,
+				    temp / 4);
+			}
+			temp = count & 3;
+			if (temp) {
+				/* receive data 1 byte at a time */
+				bus_space_read_multi_1(sc->sc_io_tag,
+				    sc->sc_io_hdl, MUSB2_REG_EPFIFO(td->ep_no),
+				    ((void *)&sc->sc_bounce_buf[count / 4]), temp);
+			}
+			usb2_copy_in(td->pc, td->offset,
+			    sc->sc_bounce_buf, count);
+
+			/* update offset and remainder */
+			td->offset += count;
+			td->remainder -= count;
+			break;
+		}
 #ifdef MUSB2_DMA_ENABLED
 		if (td->dma_enabled) {
 			/*
@@ -755,9 +811,13 @@
 				sc->sc_rx_dma[td->ep_no].error = 0;
 
 				/* start DMA job */
-				musbotg_start_rxdma(sc->sc_rx_dma + td->ep_no,
-				    buf_res.buffer, temp, td->ep_no);
-
+				if (musbotg_start_rxdma(sc->sc_rx_dma[td->ep_no].dma_chan,
+				    sc->sc_rx_dma + td->ep_no, buf_res.buffer, temp)) {
+					/* DMA failure */
+					td->error = 1;
+					/* we are complete */
+					return (0);
+				}
 				/*
 				 * Pre-advance buffer pointers because the
 				 * USB chip will update its counters:
@@ -772,15 +832,8 @@
 			}
 		}
 #endif
-		/*
-		 * Compute the least number of bytes to the next buffer
-		 * alignment address:
-		 */
-		temp = 4 - (USB_P2U(buf_res.buffer) & 3);
-
 		/* check if we can optimise */
-		if ((temp == 4) &&
-		    (buf_res.length >= 4)) {
+		if (buf_res.length >= 4) {
 
 			/* receive data 4 bytes at a time */
 			bus_space_read_multi_4(sc->sc_io_tag, sc->sc_io_hdl,
@@ -795,10 +848,6 @@
 			td->remainder -= temp;
 			continue;
 		}
-		/* minimise data transfer length */
-		if (buf_res.length > temp) {
-			buf_res.length = temp;
-		}
 		/* receive data */
 		bus_space_read_multi_1(sc->sc_io_tag, sc->sc_io_hdl,
 		    MUSB2_REG_EPFIFO(td->ep_no), buf_res.buffer,
@@ -880,6 +929,32 @@
 		if (buf_res.length > count) {
 			buf_res.length = count;
 		}
+		/* check for unaligned memory address */
+		if (USB_P2U(buf_res.buffer) & 3) {
+
+			usb2_copy_out(td->pc, td->offset,
+			    sc->sc_bounce_buf, count);
+
+			temp = count & ~3;
+
+			if (temp) {
+				/* transmit data 4 bytes at a time */
+				bus_space_write_multi_4(sc->sc_io_tag,
+				    sc->sc_io_hdl, MUSB2_REG_EPFIFO(td->ep_no),
+				    sc->sc_bounce_buf, temp / 4);
+			}
+			temp = count & 3;
+			if (temp) {
+				/* receive data 1 byte at a time */
+				bus_space_write_multi_1(sc->sc_io_tag, sc->sc_io_hdl,
+				    MUSB2_REG_EPFIFO(td->ep_no),
+				    ((void *)&sc->sc_bounce_buf[count / 4]), temp);
+			}
+			/* update offset and remainder */
+			td->offset += count;
+			td->remainder -= count;
+			break;
+		}
 #ifdef MUSB2_DMA_ENABLED
 		if (td->dma_enabled) {
 			/*
@@ -921,8 +996,13 @@
 					sc->sc_tx_dma[td->ep_no].error = 0;
 
 					/* start DMA job */
-					musbotg_start_txdma(sc->sc_tx_dma + td->ep_no,
-					    buf_res.buffer, temp, td->ep_no);
+					if (musbotg_start_txdma(sc->sc_tx_dma[td->ep_no].dma_chan,
+					    sc->sc_tx_dma + td->ep_no, buf_res.buffer, temp)) {
+						/* DMA failure */
+						td->error = 1;
+						/* we are complete */
+						return (0);
+					}
 					return (1);	/* wait for callback */
 				}
 			}
@@ -932,15 +1012,8 @@
 			}
 		}
 #endif
-		/*
-		 * Compute the least number of bytes to the next buffer
-		 * alignment address:
-		 */
-		temp = 4 - (USB_P2U(buf_res.buffer) & 3);
-
 		/* check if we can optimise */
-		if ((temp == 4) &&
-		    (buf_res.length >= 4)) {
+		if (buf_res.length >= 4) {
 
 			/* transmit data 4 bytes at a time */
 			bus_space_write_multi_4(sc->sc_io_tag, sc->sc_io_hdl,
@@ -955,10 +1028,6 @@
 			td->remainder -= temp;
 			continue;
 		}
-		/* minimise data transfer length */
-		if (buf_res.length > temp) {
-			buf_res.length = temp;
-		}
 		/* transmit data */
 		bus_space_write_multi_1(sc->sc_io_tag, sc->sc_io_hdl,
 		    MUSB2_REG_EPFIFO(td->ep_no), buf_res.buffer,
@@ -1390,7 +1459,7 @@
 					 * so there is no need for an
 					 * immediate DMA stop!
 					 */
-					musbotg_stop_rxdma_async(ep_no);
+					musbotg_stop_rxdma_async(sc->sc_tx_dma[ep_no].dma_chan);
 				}
 				sc->sc_rx_dma[ep_no].complete = 0;
 				sc->sc_rx_dma[ep_no].busy = 0;
@@ -1412,7 +1481,7 @@
 					 * so there is no need for an
 					 * immediate DMA stop!
 					 */
-					musbotg_stop_txdma_async(ep_no);
+					musbotg_stop_txdma_async(sc->sc_tx_dma[ep_no].dma_chan);
 				}
 				sc->sc_tx_dma[ep_no].complete = 0;
 				sc->sc_tx_dma[ep_no].busy = 0;
@@ -1671,13 +1740,17 @@
 
 	if (ep_dir == UE_DIR_IN) {
 
+#ifdef MUSB2_DMA_ENABLED
 		/* check if we support DMA */
-		if (musbotg_support_txdma(ep_no)) {
+		if (sc->sc_tx_dma_res[ep_no] != NULL) {
 			temp = MUSB2_MASK_CSRH_TXDMAREQMODE |
 			    MUSB2_MASK_CSRH_TXDMAREQENA;
 		} else {
 			temp = 0;
 		}
+#else
+		temp = 0;
+#endif
 
 		/* Configure endpoint */
 		switch (ep_type) {
@@ -1738,13 +1811,17 @@
 		}
 	} else {
 
+#ifdef MUSB2_DMA_ENABLED
 		/* check if we support DMA */
-		if (musbotg_support_rxdma(ep_no)) {
+		if (sc->sc_rx_dma_res[ep_no] != NULL) {
 			temp = MUSB2_MASK_CSRH_RXDMAREQMODE |
 			    MUSB2_MASK_CSRH_RXDMAREQENA;
 		} else {
 			temp = 0;
 		}
+#else
+		temp = 0;
+#endif
 
 		/* Configure endpoint */
 		switch (ep_type) {
@@ -2020,6 +2097,7 @@
 	musbotg_pull_down(sc);
 	musbotg_clocks_off(sc);
 	mtx_unlock(&sc->sc_bus.mtx);
+
 	return;
 }
 
@@ -2975,17 +3053,19 @@
 			td->ep_no = ep_no;
 			td->obj_next = last_obj;
 
+#ifdef MUSB2_DMA_ENABLED
 			/* check for DMA support */
 			if ((xfer->endpoint & (UE_DIR_IN |
 			    UE_DIR_OUT)) == UE_DIR_IN) {
-				if (musbotg_support_txdma(ep_no)) {
+				if (sc->sc_tx_dma_res[ep_no] != NULL) {
 					td->dma_enabled = 1;
 				}
 			} else {
-				if (musbotg_support_rxdma(ep_no)) {
+				if (sc->sc_rx_dma_res[ep_no] != NULL) {
 					td->dma_enabled = 1;
 				}
 			}
+#endif
 			last_obj = td;
 		}
 		parm->size[0] += sizeof(*td);

==== //depot/projects/usb/src/sys/dev/usb2/controller/musb2_otg.h#6 (text+ko) ====

@@ -294,6 +294,7 @@
 
 struct musbotg_dma {
 	struct musbotg_softc *sc;
+	uint32_t dma_chan;
 	uint8_t	busy:1;
 	uint8_t	complete:1;
 	uint8_t	error:1;
@@ -367,8 +368,9 @@
 #ifdef MUSB2_DMA_ENABLED
 	struct musbotg_dma sc_rx_dma[16];
 	struct musbotg_dma sc_tx_dma[16];
+	struct resource *sc_rx_dma_res[16];
+	struct resource *sc_tx_dma_res[16];
 #endif
-
 	struct resource *sc_io_res;
 	struct resource *sc_irq_res;
 	void   *sc_intr_hdl;
@@ -381,6 +383,7 @@
 	void   *sc_clocks_arg;
 
 	uint32_t sc_dma_align;		/* DMA buffer alignment */
+	uint32_t sc_bounce_buf[(1024 * 3) / 4];	/* bounce buffer */
 
 	uint8_t	sc_ep_max;		/* maximum number of RX and TX
 					 * endpoints supported */
@@ -405,19 +408,14 @@
 void	musbotg_interrupt(struct musbotg_softc *sc);
 
 #ifdef MUSB2_DMA_ENABLED
-void	musbotg_start_rxdma(void *arg, const void *dstaddr, uint32_t bytecount, uint32_t ep_no);
-void	musbotg_start_txdma(void *arg, const void *srcaddr, uint32_t bytecount, uint32_t ep_no);
-void	musbotg_stop_rxdma_async(uint32_t ep_no);
-void	musbotg_stop_txdma_async(uint32_t ep_no);
+/* These functions needs to be implemented for your DMA controller */
+int	musbotg_start_rxdma(uint32_t dma_chan, void *arg, const void *dstaddr, uint32_t bytecount);
+int	musbotg_start_txdma(uint32_t dma_chan, void *arg, const void *srcaddr, uint32_t bytecount);
+uint32_t musbotg_get_dma_align(void);
 void	musbotg_complete_dma_cb(void *arg, uint32_t is_error);
-uint32_t musbotg_support_rxdma(uint32_t ep_no);
-uint32_t musbotg_support_txdma(uint32_t ep_no);
-uint32_t musbotg_get_dma_align(void);
+void	musbotg_stop_rxdma_async(uint32_t dma_chan);
+void	musbotg_stop_txdma_async(uint32_t dma_chan);
 
-#else
-#define	musbotg_support_rxdma(...) 0
-#define	musbotg_support_txdma(...) 0
-#define	musbotg_get_dma_align(...) 0
 #endif
 
 #endif					/* _MUSB2_OTG_H_ */

==== //depot/projects/usb/src/sys/dev/usb2/controller/musb2_otg_atmelarm.c#4 (text+ko) ====

@@ -65,16 +65,22 @@
 static void
 musbotg_clocks_on(void *arg)
 {
+#if 0
 	struct musbotg_super_softc *sc = arg;
 
+#endif
+
 	return;
 }
 
 static void
 musbotg_clocks_off(void *arg)
 {
+#if 0
 	struct musbotg_super_softc *sc = arg;
 
+#endif
+
 	return;
 }
 
@@ -92,6 +98,11 @@
 	int err;
 	int rid;
 
+#ifdef MUSB2_DMA_ENABLED
+	int temp;
+
+#endif
+
 	if (sc == NULL) {
 		return (ENXIO);
 	}
@@ -107,6 +118,25 @@
 	    USB_GET_DMA_TAG(dev), NULL)) {
 		return (ENOMEM);
 	}
+#ifdef MUSB2_DMA_ENABLED
+	/* allocate all DMA channels */
+	for (temp = 0; temp != 16; temp++) {
+		rid = temp;		/* OUT endpoint */
+		sc->sc_otg.sc_rx_dma_res[temp] =
+		    bus_alloc_resource_any(dev, SYS_RES_DRQ, &rid, RF_ACTIVE);
+		if (sc->sc_otg.sc_rx_dma_res[temp]) {
+			sc->sc_otg.sc_rx_dma[temp].dma_chan =
+			    rman_get_start(sc->sc_otg.sc_rx_dma_res[temp]);
+		}
+		rid = temp | 0x80;	/* IN endpoint */
+		sc->sc_otg.sc_tx_dma_res[temp] =
+		    bus_alloc_resource_any(dev, SYS_RES_DRQ, &rid, RF_ACTIVE);
+		if (sc->sc_otg.sc_tx_dma_res[temp]) {
+			sc->sc_otg.sc_tx_dma[temp].dma_chan =
+			    rman_get_start(sc->sc_otg.sc_tx_dma_res[temp]);
+		}
+	}
+#endif
 	rid = 0;
 	sc->sc_otg.sc_io_res =
 	    bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
@@ -172,6 +202,10 @@
 	device_t bdev;
 	int err;
 
+#ifdef MUSB2_DMA_ENABLED
+	int temp;
+
+#endif
 	if (sc->sc_otg.sc_bus.bdev) {
 		bdev = sc->sc_otg.sc_bus.bdev;
 		device_detach(bdev);
@@ -190,11 +224,26 @@
 		    sc->sc_otg.sc_intr_hdl);
 		sc->sc_otg.sc_intr_hdl = NULL;
 	}
+#ifdef MUSB2_DMA_ENABLED
+	/* free all DMA channels */
+	for (temp = 0; temp != 16; temp++) {
+		if (sc->sc_otg.sc_rx_dma_res[temp]) {
+			bus_release_resource(dev, SYS_RES_DRQ,
+			    temp, sc->sc_otg.sc_rx_dma_res[temp]);
+		}
+		if (sc->sc_otg.sc_tx_dma_res[temp]) {
+			bus_release_resource(dev, SYS_RES_DRQ,
+			    temp | 0x80, sc->sc_otg.sc_tx_dma_res[temp]);
+		}
+	}
+#endif
+	/* free IRQ channel, if any */
 	if (sc->sc_otg.sc_irq_res) {
 		bus_release_resource(dev, SYS_RES_IRQ, 0,
 		    sc->sc_otg.sc_irq_res);
 		sc->sc_otg.sc_irq_res = NULL;
 	}
+	/* free memory resource, if any */
 	if (sc->sc_otg.sc_io_res) {
 		bus_release_resource(dev, SYS_RES_MEMORY, 0,
 		    sc->sc_otg.sc_io_res);


More information about the p4-projects mailing list