Date: Sun, 7 Sep 2008 20:35:04 GMT From: Hans Petter Selasky <hselasky@FreeBSD.org> To: Perforce Change Reviews <perforce@FreeBSD.org> Subject: PERFORCE change 149389 for review Message-ID: <200809072035.m87KZ4rb042409@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=149389 Change 149389 by hselasky@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);
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200809072035.m87KZ4rb042409>