All of lore.kernel.org
 help / color / mirror / Atom feed
From: rmorell@nvidia.com
To: Greg KH <gregkh@suse.de>
Cc: David Brownell <dbrownell@users.sourceforge.net>,
	Benoit Goby <benoit@android.com>,
	Alan Stern <stern@rowland.harvard.edu>,
	Sarah Sharp <sarah.a.sharp@linux.intel.com>,
	Matthew Wilcox <willy@linux.intel.com>,
	Ming Lei <tom.leiming@gmail.com>,
	Jacob Pan <jacob.jun.pan@intel.com>,
	Olof Johansson <olof@lixom.net>,
	Erik Gilling <konkers@android.com>,
	Colin Cross <ccross@android.com>,
	"linux-usb@vger.kernel.org" <linux-usb@vger.kernel.org>,
	"linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>
Subject: Re: [PATCH 2/2] USB: ehci: tegra: Align DMA transfers to 32 bytes
Date: Fri, 17 Dec 2010 14:42:21 -0800	[thread overview]
Message-ID: <20101217224221.GE25105@morell.nvidia.com> (raw)
In-Reply-To: <20101217223502.GB19418@suse.de>

On Fri, Dec 17, 2010 at 02:35:02PM -0800, Greg KH wrote:
> On Fri, Dec 17, 2010 at 01:58:49PM -0800, Robert Morell wrote:
> > The Tegra2 USB controller doesn't properly deal with misaligned DMA
> > buffers, causing corruption.  This is especially prevalent with USB
> > network adapters, where skbuff alignment is often in the middle of a
> > 4-byte dword.
> > 
> > To avoid this, allocate a temporary buffer for the DMA if the provided
> > buffer isn't sufficiently aligned.
> > 
> > Signed-off-by: Robert Morell <rmorell@nvidia.com>
> > Reviewed-by: Scott Williams <scwilliams@nvidia.com>
> > Reviewed-by: Janne Hellsten <jhellsten@nvidia.com>
> > ---
> >  drivers/usb/host/ehci-tegra.c |   94 +++++++++++++++++++++++++++++++++++++++++
> >  include/linux/usb.h           |    1 +
> >  2 files changed, 95 insertions(+), 0 deletions(-)
> > 
> > diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c
> > index d990c1c..a75e4db 100644
> > --- a/drivers/usb/host/ehci-tegra.c
> > +++ b/drivers/usb/host/ehci-tegra.c
> > @@ -32,6 +32,10 @@
> >  #define TEGRA_USB_USBMODE_HOST			(3 << 0)
> >  #define TEGRA_USB_PORTSC1_PTC(x)		(((x) & 0xf) << 16)
> >  
> > +#define TEGRA_USB_DMA_ALIGN 32
> > +
> > +#define URB_ALIGNED_TEMP_BUFFER 0x80000000
> > +
> >  struct tegra_ehci_context {
> >  	bool valid;
> >  	u32 command;
> > @@ -457,6 +461,94 @@ static int tegra_ehci_bus_resume(struct usb_hcd *hcd)
> >  }
> >  #endif
> >  
> > +struct temp_buffer {
> > +	void *kmalloc_ptr;
> > +	void *old_xfer_buffer;
> > +	u8 data[0];
> > +};
> > +
> > +static void free_temp_buffer(struct urb *urb)
> > +{
> > +	enum dma_data_direction dir;
> > +	struct temp_buffer *temp;
> > +
> > +	if (!(urb->transfer_flags & URB_ALIGNED_TEMP_BUFFER))
> > +		return;
> > +
> > +	dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
> > +
> > +	temp = container_of(urb->transfer_buffer, struct temp_buffer,
> > +			    data);
> > +
> > +	if (dir == DMA_FROM_DEVICE)
> > +		memcpy(temp->old_xfer_buffer, temp->data,
> > +		       urb->transfer_buffer_length);
> > +	urb->transfer_buffer = temp->old_xfer_buffer;
> > +	kfree(temp->kmalloc_ptr);
> > +
> > +	urb->transfer_flags &= ~URB_ALIGNED_TEMP_BUFFER;
> > +}
> > +
> > +static int alloc_temp_buffer(struct urb *urb, gfp_t mem_flags)
> > +{
> > +	enum dma_data_direction dir;
> > +	struct temp_buffer *temp, *kmalloc_ptr;
> > +	size_t kmalloc_size;
> > +	void *data;
> > +
> > +	if (urb->num_sgs || urb->sg ||
> > +	    urb->transfer_buffer_length == 0 ||
> > +	    !((uintptr_t)urb->transfer_buffer & (TEGRA_USB_DMA_ALIGN - 1)))
> > +		return 0;
> > +
> > +	dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
> > +
> > +	/* Allocate a buffer with enough padding for alignment */
> > +	kmalloc_size = urb->transfer_buffer_length +
> > +		sizeof(struct temp_buffer) + TEGRA_USB_DMA_ALIGN - 1;
> > +
> > +	kmalloc_ptr = kmalloc(kmalloc_size, mem_flags);
> > +	if (!kmalloc_ptr)
> > +		return -ENOMEM;
> > +
> > +	/* Position our struct temp_buffer such that data is aligned */
> > +	temp = PTR_ALIGN(kmalloc_ptr + 1, TEGRA_USB_DMA_ALIGN) - 1;
> > +
> > +	temp->kmalloc_ptr = kmalloc_ptr;
> > +	temp->old_xfer_buffer = urb->transfer_buffer;
> > +	if (dir == DMA_TO_DEVICE)
> > +		memcpy(temp->data, urb->transfer_buffer,
> > +		       urb->transfer_buffer_length);
> > +	urb->transfer_buffer = temp->data;
> > +
> > +	BUILD_BUG_ON(!(URB_ALIGNED_TEMP_BUFFER & URB_DRIVER_PRIVATE));
> 
> See below why this should be removed
> 
> > +	urb->transfer_flags |= URB_ALIGNED_TEMP_BUFFER;
> > +
> > +	return 0;
> > +}
> > +
> > +static int tegra_ehci_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
> > +				      gfp_t mem_flags)
> > +{
> > +	int ret;
> > +
> > +	ret = alloc_temp_buffer(urb, mem_flags);
> > +	if (ret)
> > +		return ret;
> > +
> > +	ret = usb_hcd_map_urb_for_dma(hcd, urb, mem_flags);
> > +	if (ret)
> > +		free_temp_buffer(urb);
> > +
> > +	return ret;
> > +}
> > +
> > +static void tegra_ehci_unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
> > +{
> > +	usb_hcd_unmap_urb_for_dma(hcd, urb);
> > +	free_temp_buffer(urb);
> > +}
> > +
> >  static const struct hc_driver tegra_ehci_hc_driver = {
> >  	.description		= hcd_name,
> >  	.product_desc		= "Tegra EHCI Host Controller",
> > @@ -472,6 +564,8 @@ static const struct hc_driver tegra_ehci_hc_driver = {
> >  	.shutdown		= tegra_ehci_shutdown,
> >  	.urb_enqueue		= ehci_urb_enqueue,
> >  	.urb_dequeue		= ehci_urb_dequeue,
> > +	.map_urb_for_dma	= tegra_ehci_map_urb_for_dma,
> > +	.unmap_urb_for_dma	= tegra_ehci_unmap_urb_for_dma,
> >  	.endpoint_disable	= ehci_endpoint_disable,
> >  	.endpoint_reset		= ehci_endpoint_reset,
> >  	.get_frame_number	= ehci_get_frame,
> > diff --git a/include/linux/usb.h b/include/linux/usb.h
> > index 35fe6ab..cd07173 100644
> > --- a/include/linux/usb.h
> > +++ b/include/linux/usb.h
> > @@ -975,6 +975,7 @@ extern int usb_disabled(void);
> >  #define URB_SETUP_MAP_SINGLE	0x00100000	/* Setup packet DMA mapped */
> >  #define URB_SETUP_MAP_LOCAL	0x00200000	/* HCD-local setup packet */
> >  #define URB_DMA_SG_COMBINED	0x00400000	/* S-G entries were combined */
> > +#define URB_DRIVER_PRIVATE	0x80000000	/* For driver-private use */
> 
> Um, what?  You are using this for a build check, which seems pointless
> as you already modified the code to not need this.
> 
> So it doesn't look like this is needed, right?

The intention was to reserve space in the URB flags for
implementation-specific use.  This placeholder should keep anybody from
adding driver-agnostic flags to that mask.  The BUILD_BUG_ON is intended
to make sure that the driver private space doesn't move out from under
the Tegra-specific flag.

Thanks,
Robert

> thanks,
> 
> greg k-h
> 

  reply	other threads:[~2010-12-17 22:43 UTC|newest]

Thread overview: 51+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-12-17 21:58 [RFC] Align tegra-ehci DMA transfers to 32B Robert Morell
2010-12-17 21:58 ` [PATCH 1/2] USB: Add driver hooks for (un)?map_urb_for_dma Robert Morell
2010-12-17 21:58 ` [PATCH 2/2] USB: ehci: tegra: Align DMA transfers to 32 bytes Robert Morell
2010-12-17 22:35   ` Greg KH
2010-12-17 22:42     ` rmorell [this message]
2010-12-17 23:09       ` Greg KH
2010-12-17 23:17         ` Oliver Neukum
2010-12-17 23:35           ` Greg KH
2010-12-17 23:50             ` rmorell
2010-12-17 23:40         ` rmorell
2010-12-18  0:37           ` Greg KH
2010-12-18  1:29             ` rmorell
2010-12-17 22:32 ` [RFC] Align tegra-ehci DMA transfers to 32B Greg KH
2010-12-17 22:44   ` rmorell
2010-12-17 23:07     ` Greg KH
2010-12-17 23:07     ` David Brownell
2010-12-18  1:49 ` [PATCH v2] " Robert Morell
2010-12-19 21:38   ` [PATCH] " Robert Morell
2011-01-06 23:20     ` [PATCH v4] " Robert Morell
2011-01-20 21:41       ` [PATCH v5] " Robert Morell
2011-01-27  3:06         ` [PATCH v6] " Robert Morell
2011-01-27  3:06         ` [PATCH 1/3] USB: HCD: Add usb_hcd prefix to exported functions Robert Morell
2011-01-27 16:01           ` Alan Stern
2011-01-27  3:06         ` [PATCH 2/3] USB: HCD: Add driver hooks for (un)?map_urb_for_dma Robert Morell
2011-01-27 16:01           ` Alan Stern
2011-01-27  3:06         ` [PATCH 3/3] USB: ehci: tegra: Align DMA transfers to 32 bytes Robert Morell
2011-02-04 19:49           ` Greg KH
     [not found]             ` <20110204194954.GA25180-U8xfFu+wG4EAvxtiuMwx3w@public.gmane.org>
2011-02-04 20:14               ` Olof Johansson
2011-02-04 20:14                 ` Olof Johansson
     [not found]                 ` <AANLkTinRtch4Pvr3GLz5wZU2xkG3FMJxxzSNAdParA7j-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2011-02-04 20:16                   ` Greg KH
2011-02-04 20:16                     ` Greg KH
     [not found]                     ` <20110204201616.GA12482-l3A5Bk7waGM@public.gmane.org>
2011-02-04 20:26                       ` rmorell-DDmLM1+adcrQT0dZR+AlfA
2011-02-04 20:26                         ` rmorell
     [not found]                         ` <20110204202640.GC1744-f3YH7lVHJt/FT5IIyIEb6QC/G2K4zDHf@public.gmane.org>
2011-02-04 20:35                           ` Greg KH
2011-02-04 20:35                             ` Greg KH
2011-01-20 21:41       ` [PATCH 1/2] USB: HCD: Add driver hooks for (un)?map_urb_for_dma Robert Morell
2011-01-23  3:46         ` Greg KH
2011-01-24 16:32         ` Alan Stern
2011-01-20 21:41       ` [PATCH 2/2] USB: ehci: tegra: Align DMA transfers to 32 bytes Robert Morell
2011-01-24 16:36         ` Alan Stern
2011-01-24 22:53           ` rmorell
2011-01-25  2:59             ` Alan Stern
2011-01-06 23:20     ` [PATCH v4 1/2] USB: HCD: Add driver hooks for (un)?map_urb_for_dma Robert Morell
2011-01-06 23:20     ` [PATCH v4 2/2] USB: ehci: tegra: Align DMA transfers to 32 bytes Robert Morell
2010-12-19 21:38   ` [PATCH 1/2] USB: Add driver hooks for (un)?map_urb_for_dma Robert Morell
2010-12-19 21:38   ` [PATCH 2/2] USB: ehci: tegra: Align DMA transfers to 32 bytes Robert Morell
2010-12-19 21:57     ` Oliver Neukum
2010-12-18  1:49 ` [PATCH v2 1/2] USB: Add driver hooks for (un)?map_urb_for_dma Robert Morell
2010-12-18 17:51   ` Greg KH
2010-12-18  1:49 ` [PATCH v2 2/2] USB: ehci: tegra: Align DMA transfers to 32 bytes Robert Morell
2010-12-18 17:52   ` Greg KH

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20101217224221.GE25105@morell.nvidia.com \
    --to=rmorell@nvidia.com \
    --cc=benoit@android.com \
    --cc=ccross@android.com \
    --cc=dbrownell@users.sourceforge.net \
    --cc=gregkh@suse.de \
    --cc=jacob.jun.pan@intel.com \
    --cc=konkers@android.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-usb@vger.kernel.org \
    --cc=olof@lixom.net \
    --cc=sarah.a.sharp@linux.intel.com \
    --cc=stern@rowland.harvard.edu \
    --cc=tom.leiming@gmail.com \
    --cc=willy@linux.intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.