From patchwork Fri Mar 12 19:12:41 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Albert Herranz X-Patchwork-Id: 47691 Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Received: from bilbo.ozlabs.org (localhost [127.0.0.1]) by ozlabs.org (Postfix) with ESMTP id A80EB100BEC for ; Sat, 13 Mar 2010 06:14:05 +1100 (EST) Received: from smtp123.mail.ukl.yahoo.com (smtp123.mail.ukl.yahoo.com [77.238.184.54]) by ozlabs.org (Postfix) with SMTP id 2FD31B7D76 for ; Sat, 13 Mar 2010 06:12:59 +1100 (EST) Received: (qmail 53549 invoked from network); 12 Mar 2010 19:12:58 -0000 DomainKey-Signature: a=rsa-sha1; q=dns; c=nofws; s=s1024; d=yahoo.es; h=Received:X-Yahoo-SMTP:X-YMail-OSG:X-Yahoo-Newman-Property:From:To:Cc:Subject:Date:Message-Id:X-Mailer:In-Reply-To:References; b=Oi1ZiJ/PyS+VWkKj5eB6M1r0FtUVJv6D2RaMwGyqPt4BaePQhS2/oOMcqcp8UQNNWyHUJYSN7mJH9TMgzED7+v+y68PdhYnDBryMhLVlmo0q4uhoLsuB9FKtD3L1owyKbJOODocxkJa6ftRfmwvcUnbvMPBRKPczTens8nZEDyY= ; Received: from 41.Red-83-55-221.dynamicIP.rima-tde.net (albert_herranz@83.55.221.41 with login) by smtp123.mail.ukl.yahoo.com with SMTP; 12 Mar 2010 19:12:57 +0000 GMT X-Yahoo-SMTP: czee06uswBAtfIYshc.kP27UlfEXaxwWNSjJ X-YMail-OSG: 70ej.C0VM1mcClNj3t5j25HeC7UxmpNDlrhxe24GeTF6OtpoJFYsXp_wKT0.HmEK9B4xCYEm9EWlZnycf8BzBw4tGHTP1JFAm_BeUF.79KrxhP9RjkaX9GPoJ3IHrKn7ujgB2pvoZUIlcXnYCOOB9hVxDAvY8vjoJmS.AmIXhFSn4iva2uSDiiW27dTqxiaKYz8LIhPMGbtMhTUU8oINiPSzwXEXKKglI0ASRpxRXPiVIkvXH_PCHg2j.oHhAZ3f.4ZdKT8nKFB2q.XgbP9jswt8q4lpIfaz X-Yahoo-Newman-Property: ymail-3 From: Albert Herranz To: linux-usb@vger.kernel.org, linuxppc-dev@lists.ozlabs.org Subject: [PATCH v4 06/11] USB: refactor unmap_urb_for_dma/map_urb_for_dma Date: Fri, 12 Mar 2010 20:12:41 +0100 Message-Id: <1268421166-4791-7-git-send-email-albert_herranz@yahoo.es> X-Mailer: git-send-email 1.6.3.3 In-Reply-To: <1268421166-4791-1-git-send-email-albert_herranz@yahoo.es> References: <1268421166-4791-1-git-send-email-albert_herranz@yahoo.es> Cc: Albert Herranz X-BeenThere: linuxppc-dev@lists.ozlabs.org X-Mailman-Version: 2.1.13 Precedence: list List-Id: Linux on PowerPC Developers Mail List List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: linuxppc-dev-bounces+patchwork-incoming=ozlabs.org@lists.ozlabs.org Errors-To: linuxppc-dev-bounces+patchwork-incoming=ozlabs.org@lists.ozlabs.org Split unmap_urb_for_dma() and map_urb_for_dma() into smaller pieces to make the code easier to read and maintain. This patch adds four new URB flags which are used by map_urb_for_dma() to mark URBs with the exact method used to map the setup packet and/or the transfer buffer. These flags are checked too at unmap_urb_for_dma() time to determine how to unmap the setup packet and/or the transfer buffer. The flags are cleared when the actual unmap happens. No functional change. Signed-off-by: Albert Herranz --- drivers/usb/core/hcd.c | 211 +++++++++++++++++++++++++++++++----------------- include/linux/usb.h | 5 + 2 files changed, 143 insertions(+), 73 deletions(-) diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 80995ef..44ad710 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -1260,106 +1260,171 @@ static void hcd_free_coherent(struct usb_bus *bus, dma_addr_t *dma_handle, *dma_handle = 0; } -static int map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb, - gfp_t mem_flags) +static void unmap_urb_setup_packet(struct usb_hcd *hcd, struct urb *urb) +{ + if (urb->transfer_flags & URB_SETUP_DMA_MAPPED) { + urb->transfer_flags &= ~URB_SETUP_DMA_MAPPED; + dma_unmap_single(hcd->self.controller, urb->setup_dma, + sizeof(struct usb_ctrlrequest), + DMA_TO_DEVICE); + } else if (urb->transfer_flags & URB_SETUP_BOUNCE_MAPPED) { + /* bounce from "local" memory */ + urb->transfer_flags &= ~URB_SETUP_BOUNCE_MAPPED; + hcd_free_coherent(urb->dev->bus, &urb->setup_dma, + (void **)&urb->setup_packet, + sizeof(struct usb_ctrlrequest), + DMA_TO_DEVICE); + } else { + /* nothing to do for PIO-based controller requests */ + } +} + +static void unmap_urb_transfer_buffer(struct usb_hcd *hcd, struct urb *urb) { enum dma_data_direction dir; - int ret = 0; - /* Map the URB's buffers for DMA access. - * Lower level HCD code should use *_dma exclusively, - * unless it uses pio or talks to another transport, - * or uses the provided scatter gather list for bulk. - */ + dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE; + if (urb->transfer_flags & URB_TRANSFER_DMA_MAPPED) { + urb->transfer_flags &= ~URB_TRANSFER_DMA_MAPPED; + dma_unmap_single(hcd->self.controller, + urb->transfer_dma, + urb->transfer_buffer_length, + dir); + } else if (urb->transfer_flags & URB_TRANSFER_BOUNCE_MAPPED) { + /* bounce from "local" memory */ + urb->transfer_flags &= ~URB_TRANSFER_BOUNCE_MAPPED; + hcd_free_coherent(urb->dev->bus, &urb->transfer_dma, + &urb->transfer_buffer, + urb->transfer_buffer_length, + dir); + } else { + /* nothing to do for PIO-based controller requests */ + } +} + +static void unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb) +{ if (is_root_hub(urb->dev)) + return; + + unmap_urb_setup_packet(hcd, urb); + unmap_urb_transfer_buffer(hcd, urb); +} + +static int urb_needs_setup_map(struct usb_hcd *hcd, struct urb *urb) +{ + /* setup mappings are required only for control requests */ + if (!usb_endpoint_xfer_control(&urb->ep->desc)) + return 0; + + /* If the caller set URB_NO_SETUP_DMA_MAP then no mapping is needed */ + if ((urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) + return 0; + + return 1; +} + +static int urb_needs_transfer_map(struct usb_hcd *hcd, struct urb *urb) +{ + /* don't need to map anything if there's nothing to map */ + if (urb->transfer_buffer_length == 0) return 0; - if (usb_endpoint_xfer_control(&urb->ep->desc) - && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) { + /* If the caller set URB_NO_SETUP_DMA_MAP then no mapping is needed */ + if ((urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) + return 0; + + return 1; +} + +static int map_urb_setup_packet(struct usb_hcd *hcd, struct urb *urb, + gfp_t mem_flags) +{ + int ret; + + if (urb_needs_setup_map(hcd, urb)) { if (hcd->self.uses_dma) { urb->setup_dma = dma_map_single( - hcd->self.controller, - urb->setup_packet, - sizeof(struct usb_ctrlrequest), - DMA_TO_DEVICE); + hcd->self.controller, + urb->setup_packet, + sizeof(struct usb_ctrlrequest), + DMA_TO_DEVICE); if (dma_mapping_error(hcd->self.controller, - urb->setup_dma)) + urb->setup_dma)) return -EAGAIN; - } else if (hcd->driver->flags & HCD_LOCAL_MEM) - ret = hcd_alloc_coherent( - urb->dev->bus, mem_flags, - &urb->setup_dma, - (void **)&urb->setup_packet, - sizeof(struct usb_ctrlrequest), - DMA_TO_DEVICE); + urb->transfer_flags |= URB_SETUP_DMA_MAPPED; + } else if (hcd->driver->flags & HCD_LOCAL_MEM) { + /* bounce to "local" memory */ + ret = hcd_alloc_coherent(urb->dev->bus, mem_flags, + &urb->setup_dma, + (void **)&urb->setup_packet, + sizeof(struct usb_ctrlrequest), + DMA_TO_DEVICE); + if (ret) + return ret; + urb->transfer_flags |= URB_SETUP_BOUNCE_MAPPED; + } else { + /* nothing to do for PIO-based controller requests */ + } } + return 0; +} + +static int map_urb_transfer_buffer(struct usb_hcd *hcd, struct urb *urb, + gfp_t mem_flags) +{ + enum dma_data_direction dir; + int ret; dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE; - if (ret == 0 && urb->transfer_buffer_length != 0 - && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) { + if (urb_needs_transfer_map(hcd, urb)) { if (hcd->self.uses_dma) { urb->transfer_dma = dma_map_single ( - hcd->self.controller, - urb->transfer_buffer, - urb->transfer_buffer_length, - dir); + hcd->self.controller, + urb->transfer_buffer, + urb->transfer_buffer_length, + dir); if (dma_mapping_error(hcd->self.controller, - urb->transfer_dma)) + urb->transfer_dma)) return -EAGAIN; + urb->transfer_flags |= URB_TRANSFER_DMA_MAPPED; } else if (hcd->driver->flags & HCD_LOCAL_MEM) { - ret = hcd_alloc_coherent( - urb->dev->bus, mem_flags, - &urb->transfer_dma, - &urb->transfer_buffer, - urb->transfer_buffer_length, - dir); - - if (ret && usb_endpoint_xfer_control(&urb->ep->desc) - && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) - hcd_free_coherent(urb->dev->bus, - &urb->setup_dma, - (void **)&urb->setup_packet, - sizeof(struct usb_ctrlrequest), - DMA_TO_DEVICE); + /* bounce to "local" memory */ + ret = hcd_alloc_coherent(urb->dev->bus, mem_flags, + &urb->transfer_dma, + &urb->transfer_buffer, + urb->transfer_buffer_length, + dir); + if (ret) + return ret; + urb->transfer_flags |= URB_TRANSFER_BOUNCE_MAPPED; + } else { + /* nothing to do for PIO-based controller requests */ } } - return ret; + return 0; } -static void unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb) +static int map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb, + gfp_t mem_flags) { - enum dma_data_direction dir; + int error; + /* Map the URB's buffers for DMA access. + * Lower level HCD code should use *_dma exclusively, + * unless it uses pio or talks to another transport, + * or uses the provided scatter gather list for bulk. + */ if (is_root_hub(urb->dev)) - return; - - if (usb_endpoint_xfer_control(&urb->ep->desc) - && !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) { - if (hcd->self.uses_dma) - dma_unmap_single(hcd->self.controller, urb->setup_dma, - sizeof(struct usb_ctrlrequest), - DMA_TO_DEVICE); - else if (hcd->driver->flags & HCD_LOCAL_MEM) - hcd_free_coherent(urb->dev->bus, &urb->setup_dma, - (void **)&urb->setup_packet, - sizeof(struct usb_ctrlrequest), - DMA_TO_DEVICE); - } + return 0; - dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE; - if (urb->transfer_buffer_length != 0 - && !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)) { - if (hcd->self.uses_dma) - dma_unmap_single(hcd->self.controller, - urb->transfer_dma, - urb->transfer_buffer_length, - dir); - else if (hcd->driver->flags & HCD_LOCAL_MEM) - hcd_free_coherent(urb->dev->bus, &urb->transfer_dma, - &urb->transfer_buffer, - urb->transfer_buffer_length, - dir); + error = map_urb_setup_packet(hcd, urb, mem_flags); + if (!error) { + error = map_urb_transfer_buffer(hcd, urb, mem_flags); + if (error) + unmap_urb_setup_packet(hcd, urb); } + return error; } /*-------------------------------------------------------------------------*/ diff --git a/include/linux/usb.h b/include/linux/usb.h index d7ace1b..5e99cbd 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h @@ -985,6 +985,11 @@ extern int usb_disabled(void); #define URB_DIR_OUT 0 #define URB_DIR_MASK URB_DIR_IN +#define URB_SETUP_DMA_MAPPED 0x1000 /* via dma_map_single */ +#define URB_SETUP_BOUNCE_MAPPED 0x2000 /* via hcd_alloc_coherent */ +#define URB_TRANSFER_DMA_MAPPED 0x4000 /* via dma_map_single */ +#define URB_TRANSFER_BOUNCE_MAPPED 0x8000 /* via hcd_alloc_coherent */ + struct usb_iso_packet_descriptor { unsigned int offset; unsigned int length; /* expected length */