This is a note to let you know that I've just added the patch titled usb: musb: gadget: Unmapping the dma buffer when switching to PIO mode to my gregkh-2.6 tree which can be found in directory form at: http://www.kernel.org/pub/linux/kernel/people/gregkh/gregkh-2.6/patches/ and in git form at: git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/patches.git The filename of this patch is: usb-musb-gadget-unmapping-the-dma-buffer-when-switching-to-pio-mode.patch The patch will show up in the next release of the linux-next tree (usually sometime within the next 24 hours during the week.) If this patch meets the merge guidelines for a bugfix, it should be merged into Linus's tree before the next major kernel release. If not, it will be merged into Linus's tree during the next merge window. Either way, you will probably be copied on the patch when it gets sent to Linus for merging so that others can see what is happening in kernel development. If you have any questions about this process, please let me know. >From balbi@xxxxxx Tue Oct 5 13:29:53 2010 From: Felipe Balbi <balbi@xxxxxx> To: Greg KH <greg@xxxxxxxxx> Cc: Linux USB Mailing List <linux-usb@xxxxxxxxxxxxxxx>, Hema HK <hemahk@xxxxxx>, Felipe Balbi <balbi@xxxxxx> Subject: usb: musb: gadget: Unmapping the dma buffer when switching to PIO mode Date: Fri, 24 Sep 2010 13:44:08 +0300 Message-Id: <1285325055-1247-8-git-send-email-balbi@xxxxxx> From: Hema HK <hemahk@xxxxxx> Buffer is mapped to dma when dma channel is allocated. buffer needs to be unmapped when fallback to PIO mode if dma channel_program fails. Signed-off-by: Hema HK <hemahk@xxxxxx> Signed-off-by: Felipe Balbi <balbi@xxxxxx> Reviewed-by: Ming Lei <tom.leiming@xxxxxxxxx> Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxx> --- drivers/usb/musb/musb_gadget.c | 122 +++++++++++++++++++++++++++-------------- 1 file changed, 82 insertions(+), 40 deletions(-) --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -92,6 +92,60 @@ /* ----------------------------------------------------------------------- */ +/* Maps the buffer to dma */ + +static inline void map_dma_buffer(struct musb_request *request, + struct musb *musb) +{ + if (request->request.dma == DMA_ADDR_INVALID) { + request->request.dma = dma_map_single( + musb->controller, + request->request.buf, + request->request.length, + request->tx + ? DMA_TO_DEVICE + : DMA_FROM_DEVICE); + request->mapped = 1; + } else { + dma_sync_single_for_device(musb->controller, + request->request.dma, + request->request.length, + request->tx + ? DMA_TO_DEVICE + : DMA_FROM_DEVICE); + request->mapped = 0; + } +} + +/* Unmap the buffer from dma and maps it back to cpu */ +static inline void unmap_dma_buffer(struct musb_request *request, + struct musb *musb) +{ + if (request->request.dma == DMA_ADDR_INVALID) { + DBG(20, "not unmapping a never mapped buffer\n"); + return; + } + + if (request->mapped) { + dma_unmap_single(musb->controller, + request->request.dma, + request->request.length, + request->tx + ? DMA_TO_DEVICE + : DMA_FROM_DEVICE); + request->request.dma = DMA_ADDR_INVALID; + request->mapped = 0; + } else { + dma_sync_single_for_cpu(musb->controller, + request->request.dma, + request->request.length, + request->tx + ? DMA_TO_DEVICE + : DMA_FROM_DEVICE); + + } +} + /* * Immediately complete a request. * @@ -119,24 +173,8 @@ __acquires(ep->musb->lock) ep->busy = 1; spin_unlock(&musb->lock); - if (is_dma_capable()) { - if (req->mapped) { - dma_unmap_single(musb->controller, - req->request.dma, - req->request.length, - req->tx - ? DMA_TO_DEVICE - : DMA_FROM_DEVICE); - req->request.dma = DMA_ADDR_INVALID; - req->mapped = 0; - } else if (req->request.dma != DMA_ADDR_INVALID) - dma_sync_single_for_cpu(musb->controller, - req->request.dma, - req->request.length, - req->tx - ? DMA_TO_DEVICE - : DMA_FROM_DEVICE); - } + if (is_dma_capable() && ep->dma) + unmap_dma_buffer(req, musb); if (request->status == 0) DBG(5, "%s done request %p, %d/%d\n", ep->end_point.name, request, @@ -298,7 +336,7 @@ static void txstate(struct musb *musb, s csr); #ifndef CONFIG_MUSB_PIO_ONLY - if (is_dma_capable() && musb_ep->dma) { + if (is_dma_capable() && !musb_ep->dma && musb->dma_controller) { struct dma_controller *c = musb->dma_controller; size_t request_size; @@ -395,6 +433,13 @@ static void txstate(struct musb *musb, s #endif if (!use_dma) { + /* + * Unmap the dma buffer back to cpu if dma channel + * programming fails + */ + if (is_dma_capable() && musb_ep->dma) + unmap_dma_buffer(req, musb); + musb_write_fifo(musb_ep->hw_ep, fifo_count, (u8 *) (request->buf + request->actual)); request->actual += fifo_count; @@ -711,6 +756,20 @@ static void rxstate(struct musb *musb, s return; } #endif + /* + * Unmap the dma buffer back to cpu if dma channel + * programming fails. This buffer is mapped if the + * channel allocation is successful + */ + if (is_dma_capable() && musb_ep->dma) { + unmap_dma_buffer(req, musb); + + /* Clear DMAENAB for the + * PIO mode transfer + */ + csr &= ~MUSB_RXCSR_DMAENAB; + musb_writew(epio, MUSB_RXCSR, csr); + } musb_read_fifo(musb_ep->hw_ep, fifo_count, (u8 *) (request->buf + request->actual)); @@ -1153,28 +1212,11 @@ static int musb_gadget_queue(struct usb_ request->epnum = musb_ep->current_epnum; request->tx = musb_ep->is_in; - if (is_dma_capable() && musb_ep->dma) { - if (request->request.dma == DMA_ADDR_INVALID) { - request->request.dma = dma_map_single( - musb->controller, - request->request.buf, - request->request.length, - request->tx - ? DMA_TO_DEVICE - : DMA_FROM_DEVICE); - request->mapped = 1; - } else { - dma_sync_single_for_device(musb->controller, - request->request.dma, - request->request.length, - request->tx - ? DMA_TO_DEVICE - : DMA_FROM_DEVICE); - request->mapped = 0; - } - } else if (!req->buf) { + if (is_dma_capable() && musb_ep->dma) + map_dma_buffer(request, musb); + else if (!req->buf) return -ENODATA; - } else + else request->mapped = 0; spin_lock_irqsave(&musb->lock, lockflags); -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html