Moreover, instead of keeping a boolean musb_request.mapped state, three states are maintained. This allows the unmap operation to be called from more than one place and to keep track if the mapping is done by the musb driver or anyone else. DMA mappings are done after checking musb_ep->dma so where applicable checks for it are removed. And where possible, checks for is_dma_capable() are merged with map state check Signed-off-by: Mian Yousaf Kaukab <mian.yousaf.kaukab@xxxxxxxxxxxxxx> --- This patch is based on git://gitorious.org/usb/usb.git musb-hw drivers/usb/musb/musb_gadget.c | 122 +++++++++++++++++++++++++--------------- drivers/usb/musb/musb_gadget.h | 8 ++- 2 files changed, 84 insertions(+), 46 deletions(-) diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index edff014..7ee8467 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -92,6 +92,75 @@ /* ----------------------------------------------------------------------- */ +#define is_req_mapped(req) (is_dma_capable() && (req->map_state != UN_MAPPED)) + +static void musb_dma_map_request(struct musb *musb, + struct musb_ep *musb_ep, struct musb_request *req) +{ + int compatible = true; + struct dma_controller *dma = musb->dma_controller; + + req->map_state = UN_MAPPED; + + if (!is_dma_capable() || !musb_ep->dma) + return; + + /* Check if DMA engine can handle this request. + * DMA code must reject the USB request explicitly. + * Default behaviour is to map the request. + */ + if (dma->is_req_compatible) + compatible = dma->is_req_compatible(dma, musb_ep, + &req->request); + + if (!compatible) + return; + + if (req->request.dma == DMA_ADDR_INVALID) { + req->request.dma = dma_map_single( + musb->controller, + req->request.buf, + req->request.length, + req->tx + ? DMA_TO_DEVICE + : DMA_FROM_DEVICE); + req->map_state = MUSB_MAPPED; + } else { + dma_sync_single_for_device(musb->controller, + req->request.dma, + req->request.length, + req->tx + ? DMA_TO_DEVICE + : DMA_FROM_DEVICE); + req->map_state = PRE_MAPPED; + } +} + +static void musb_dma_unmap_request(struct musb *musb, struct musb_request *req) +{ + if (!is_req_mapped(req)) + return; + + if (req->map_state == MUSB_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; + } else { /* PRE_MAPPED */ + dma_sync_single_for_cpu(musb->controller, + req->request.dma, + req->request.length, + req->tx + ? DMA_TO_DEVICE + : DMA_FROM_DEVICE); + } + + req->map_state = UN_MAPPED; +} + /* * Immediately complete a request. * @@ -119,24 +188,9 @@ __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); - } + + musb_dma_unmap_request(musb, req); + if (request->status == 0) DBG(5, "%s done request %p, %d/%d\n", ep->end_point.name, request, @@ -298,7 +352,7 @@ static void txstate(struct musb *musb, struct musb_request *req) csr); #ifndef CONFIG_MUSB_PIO_ONLY - if (is_dma_capable() && musb_ep->dma) { + if (is_req_mapped(req)) { struct dma_controller *c = musb->dma_controller; size_t request_size; @@ -583,7 +637,7 @@ static void rxstate(struct musb *musb, struct musb_request *req) return; } - if (is_cppi_enabled() && musb_ep->dma) { + if (is_cppi_enabled() && is_req_mapped(req)) { struct dma_controller *c = musb->dma_controller; struct dma_channel *channel = musb_ep->dma; @@ -614,7 +668,7 @@ static void rxstate(struct musb *musb, struct musb_request *req) len = musb_readw(epio, MUSB_RXCOUNT); if (request->actual < request->length) { #ifdef CONFIG_USB_INVENTRA_DMA - if (is_dma_capable() && musb_ep->dma) { + if (is_req_mapped(req)) { struct dma_controller *c; struct dma_channel *channel; int use_dma = 0; @@ -696,7 +750,7 @@ static void rxstate(struct musb *musb, struct musb_request *req) fifo_count = min_t(unsigned, len, fifo_count); #ifdef CONFIG_USB_TUSB_OMAP_DMA - if (tusb_dma_omap() && musb_ep->dma) { + if (tusb_dma_omap() && is_req_mapped(req)) { struct dma_controller *c = musb->dma_controller; struct dma_channel *channel = musb_ep->dma; u32 dma_addr = request->dma + request->actual; @@ -1150,29 +1204,7 @@ static int musb_gadget_queue(struct usb_ep *ep, struct usb_request *req, 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) { - return -ENODATA; - } else - request->mapped = 0; + musb_dma_map_request(musb, musb_ep, request); spin_lock_irqsave(&musb->lock, lockflags); diff --git a/drivers/usb/musb/musb_gadget.h b/drivers/usb/musb/musb_gadget.h index dec8dc0..e481cc8 100644 --- a/drivers/usb/musb/musb_gadget.h +++ b/drivers/usb/musb/musb_gadget.h @@ -35,13 +35,19 @@ #ifndef __MUSB_GADGET_H #define __MUSB_GADGET_H +enum dma_map_state { + UN_MAPPED = 0, + PRE_MAPPED, + MUSB_MAPPED +}; + struct musb_request { struct usb_request request; struct musb_ep *ep; struct musb *musb; u8 tx; /* endpoint direction */ u8 epnum; - u8 mapped; + enum dma_map_state map_state; }; static inline struct musb_request *to_musb_request(struct usb_request *req) -- 1.6.3.3 -- 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