All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] media: Fix a UVC performance problem on systems with non-coherent DMA.
@ 2011-08-18 13:28 Al Cooper
  2011-08-26  9:23 ` Laurent Pinchart
  0 siblings, 1 reply; 2+ messages in thread
From: Al Cooper @ 2011-08-18 13:28 UTC (permalink / raw)
  To: laurent.pinchart, linux-media, cernekee; +Cc: Al Cooper

The UVC driver uses usb_alloc_coherent() to allocate DMA data buffers.
On systems without coherent DMA this ends up allocating buffers in
uncached memory. The subsequent memcpy's done to coalesce the DMA
chunks into contiguous buffers then run VERY slowly. On a MIPS test
system the memcpy is about 200 times slower. This issue prevents the
system from keeping up with 720p YUYV data at 10fps.

The following patch uses kmalloc to alloc the DMA buffers instead of
uab_alloc_coherent on systems without coherent DMA. With this patch
the system was easily able to keep up with 720p at 10fps.

Signed-off-by: Al Cooper <alcooperx@gmail.com>
---
 drivers/media/video/uvc/uvc_video.c |   18 +++++++++++++++++-
 1 files changed, 17 insertions(+), 1 deletions(-)

diff --git a/drivers/media/video/uvc/uvc_video.c b/drivers/media/video/uvc/uvc_video.c
index 4999479..30c18b4 100644
--- a/drivers/media/video/uvc/uvc_video.c
+++ b/drivers/media/video/uvc/uvc_video.c
@@ -790,8 +790,12 @@ static void uvc_free_urb_buffers(struct uvc_streaming *stream)
 
 	for (i = 0; i < UVC_URBS; ++i) {
 		if (stream->urb_buffer[i]) {
+#ifndef CONFIG_DMA_NONCOHERENT
 			usb_free_coherent(stream->dev->udev, stream->urb_size,
 				stream->urb_buffer[i], stream->urb_dma[i]);
+#else
+			kfree(stream->urb_buffer[i]);
+#endif
 			stream->urb_buffer[i] = NULL;
 		}
 	}
@@ -831,9 +835,15 @@ static int uvc_alloc_urb_buffers(struct uvc_streaming *stream,
 	for (; npackets > 1; npackets /= 2) {
 		for (i = 0; i < UVC_URBS; ++i) {
 			stream->urb_size = psize * npackets;
+#ifndef CONFIG_DMA_NONCOHERENT
 			stream->urb_buffer[i] = usb_alloc_coherent(
 				stream->dev->udev, stream->urb_size,
 				gfp_flags | __GFP_NOWARN, &stream->urb_dma[i]);
+#else
+			stream->urb_buffer[i] =
+			    kmalloc(stream->urb_size, gfp_flags | __GFP_NOWARN);
+#endif
+
 			if (!stream->urb_buffer[i]) {
 				uvc_free_urb_buffers(stream);
 				break;
@@ -908,10 +918,14 @@ static int uvc_init_video_isoc(struct uvc_streaming *stream,
 		urb->context = stream;
 		urb->pipe = usb_rcvisocpipe(stream->dev->udev,
 				ep->desc.bEndpointAddress);
+#ifndef CONFIG_DMA_NONCOHERENT
 		urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
+		urb->transfer_dma = stream->urb_dma[i];
+#else
+		urb->transfer_flags = URB_ISO_ASAP;
+#endif
 		urb->interval = ep->desc.bInterval;
 		urb->transfer_buffer = stream->urb_buffer[i];
-		urb->transfer_dma = stream->urb_dma[i];
 		urb->complete = uvc_video_complete;
 		urb->number_of_packets = npackets;
 		urb->transfer_buffer_length = size;
@@ -969,8 +983,10 @@ static int uvc_init_video_bulk(struct uvc_streaming *stream,
 		usb_fill_bulk_urb(urb, stream->dev->udev, pipe,
 			stream->urb_buffer[i], size, uvc_video_complete,
 			stream);
+#ifndef CONFIG_DMA_NONCOHERENT
 		urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
 		urb->transfer_dma = stream->urb_dma[i];
+#endif
 
 		stream->urb[i] = urb;
 	}
-- 
1.7.3.2



^ permalink raw reply related	[flat|nested] 2+ messages in thread

* Re: [PATCH] media: Fix a UVC performance problem on systems with non-coherent DMA.
  2011-08-18 13:28 [PATCH] media: Fix a UVC performance problem on systems with non-coherent DMA Al Cooper
@ 2011-08-26  9:23 ` Laurent Pinchart
  0 siblings, 0 replies; 2+ messages in thread
From: Laurent Pinchart @ 2011-08-26  9:23 UTC (permalink / raw)
  To: Al Cooper; +Cc: linux-media, cernekee

Hi Al,

Thanks for the patch.

On Thursday 18 August 2011 15:28:29 Al Cooper wrote:
> The UVC driver uses usb_alloc_coherent() to allocate DMA data buffers.
> On systems without coherent DMA this ends up allocating buffers in
> uncached memory. The subsequent memcpy's done to coalesce the DMA
> chunks into contiguous buffers then run VERY slowly. On a MIPS test
> system the memcpy is about 200 times slower. This issue prevents the
> system from keeping up with 720p YUYV data at 10fps.
> 
> The following patch uses kmalloc to alloc the DMA buffers instead of
> uab_alloc_coherent on systems without coherent DMA. With this patch
> the system was easily able to keep up with 720p at 10fps.
> 
> Signed-off-by: Al Cooper <alcooperx@gmail.com>

Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

I will push it to v3.2.

> ---
>  drivers/media/video/uvc/uvc_video.c |   18 +++++++++++++++++-
>  1 files changed, 17 insertions(+), 1 deletions(-)
> 
> diff --git a/drivers/media/video/uvc/uvc_video.c
> b/drivers/media/video/uvc/uvc_video.c index 4999479..30c18b4 100644
> --- a/drivers/media/video/uvc/uvc_video.c
> +++ b/drivers/media/video/uvc/uvc_video.c
> @@ -790,8 +790,12 @@ static void uvc_free_urb_buffers(struct uvc_streaming
> *stream)
> 
>  	for (i = 0; i < UVC_URBS; ++i) {
>  		if (stream->urb_buffer[i]) {
> +#ifndef CONFIG_DMA_NONCOHERENT
>  			usb_free_coherent(stream->dev->udev, stream->urb_size,
>  				stream->urb_buffer[i], stream->urb_dma[i]);
> +#else
> +			kfree(stream->urb_buffer[i]);
> +#endif
>  			stream->urb_buffer[i] = NULL;
>  		}
>  	}
> @@ -831,9 +835,15 @@ static int uvc_alloc_urb_buffers(struct uvc_streaming
> *stream, for (; npackets > 1; npackets /= 2) {
>  		for (i = 0; i < UVC_URBS; ++i) {
>  			stream->urb_size = psize * npackets;
> +#ifndef CONFIG_DMA_NONCOHERENT
>  			stream->urb_buffer[i] = usb_alloc_coherent(
>  				stream->dev->udev, stream->urb_size,
>  				gfp_flags | __GFP_NOWARN, &stream->urb_dma[i]);
> +#else
> +			stream->urb_buffer[i] =
> +			    kmalloc(stream->urb_size, gfp_flags | __GFP_NOWARN);
> +#endif
> +
>  			if (!stream->urb_buffer[i]) {
>  				uvc_free_urb_buffers(stream);
>  				break;
> @@ -908,10 +918,14 @@ static int uvc_init_video_isoc(struct uvc_streaming
> *stream, urb->context = stream;
>  		urb->pipe = usb_rcvisocpipe(stream->dev->udev,
>  				ep->desc.bEndpointAddress);
> +#ifndef CONFIG_DMA_NONCOHERENT
>  		urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
> +		urb->transfer_dma = stream->urb_dma[i];
> +#else
> +		urb->transfer_flags = URB_ISO_ASAP;
> +#endif
>  		urb->interval = ep->desc.bInterval;
>  		urb->transfer_buffer = stream->urb_buffer[i];
> -		urb->transfer_dma = stream->urb_dma[i];
>  		urb->complete = uvc_video_complete;
>  		urb->number_of_packets = npackets;
>  		urb->transfer_buffer_length = size;
> @@ -969,8 +983,10 @@ static int uvc_init_video_bulk(struct uvc_streaming
> *stream, usb_fill_bulk_urb(urb, stream->dev->udev, pipe,
>  			stream->urb_buffer[i], size, uvc_video_complete,
>  			stream);
> +#ifndef CONFIG_DMA_NONCOHERENT
>  		urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
>  		urb->transfer_dma = stream->urb_dma[i];
> +#endif
> 
>  		stream->urb[i] = urb;
>  	}

-- 
Regards,

Laurent Pinchart

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2011-08-26  9:23 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-08-18 13:28 [PATCH] media: Fix a UVC performance problem on systems with non-coherent DMA Al Cooper
2011-08-26  9:23 ` Laurent Pinchart

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.