The patch number 10295 was added via Laurent Pinchart 
<laurent.pinch...@skynet.be>
to http://linuxtv.org/hg/v4l-dvb master development tree.

Kernel patches in this development tree may be modified to be backward
compatible with older kernels. Compatibility modifications will be
removed before inclusion into the mainstream Kernel

If anyone has any objections, please let us know by sending a message to:
        Linux Media Mailing List <linux-me...@vger.kernel.org>

------

From: Laurent Pinchart  <laurent.pinch...@skynet.be>
uvcvideo: Retry URB buffers allocation when the system is low on memory.


URB buffers for video transfers are sized to UVC_MAX_PACKETS bulk/isochronous
packets by default. If the system is too low on memory try successively
smaller numbers of packets until allocation succeeds.

Priority: normal

Signed-off-by: Laurent Pinchart <laurent.pinch...@skynet.be>
Reviewed-by: Johannes Berg <johan...@sipsolutions.net>
Tested-by: Johannes Berg <johan...@sipsolutions.net>


---

 linux/drivers/media/video/uvc/uvc_video.c |   93 +++++++++++-----------
 linux/drivers/media/video/uvc/uvcvideo.h  |    6 -
 2 files changed, 51 insertions(+), 48 deletions(-)

diff -r 843faef8fd17 -r 080861af82f1 linux/drivers/media/video/uvc/uvc_video.c
--- a/linux/drivers/media/video/uvc/uvc_video.c Wed Jan 14 16:49:11 2009 +0100
+++ b/linux/drivers/media/video/uvc/uvc_video.c Sun Jan 18 21:46:30 2009 +0100
@@ -703,27 +703,47 @@ static void uvc_free_urb_buffers(struct 
  * already allocated when resuming from suspend, in which case it will
  * return without touching the buffers.
  *
- * Return 0 on success or -ENOMEM when out of memory.
+ * Limit the buffer size to UVC_MAX_PACKETS bulk/isochronous packets. If the
+ * system is too low on memory try successively smaller numbers of packets
+ * until allocation succeeds.
+ *
+ * Return the number of allocated packets on success or 0 when out of memory.
  */
 static int uvc_alloc_urb_buffers(struct uvc_video_device *video,
-       unsigned int size)
-{
+       unsigned int size, unsigned int psize, gfp_t gfp_flags)
+{
+       unsigned int npackets;
        unsigned int i;
 
        /* Buffers are already allocated, bail out. */
        if (video->urb_size)
                return 0;
 
-       for (i = 0; i < UVC_URBS; ++i) {
-               video->urb_buffer[i] = usb_buffer_alloc(video->dev->udev,
-                       size, GFP_KERNEL, &video->urb_dma[i]);
-               if (video->urb_buffer[i] == NULL) {
-                       uvc_free_urb_buffers(video);
-                       return -ENOMEM;
-               }
-       }
-
-       video->urb_size = size;
+       /* Compute the number of packets. Bulk endpoints might transfer UVC
+        * payloads accross multiple URBs.
+        */
+       npackets = DIV_ROUND_UP(size, psize);
+       if (npackets > UVC_MAX_PACKETS)
+               npackets = UVC_MAX_PACKETS;
+
+       /* Retry allocations until one succeed. */
+       for (; npackets > 1; npackets /= 2) {
+               for (i = 0; i < UVC_URBS; ++i) {
+                       video->urb_buffer[i] = usb_buffer_alloc(
+                               video->dev->udev, psize * npackets,
+                               gfp_flags | __GFP_NOWARN, &video->urb_dma[i]);
+                       if (!video->urb_buffer[i]) {
+                               uvc_free_urb_buffers(video);
+                               break;
+                       }
+               }
+
+               if (i == UVC_URBS) {
+                       video->urb_size = psize * npackets;
+                       return npackets;
+               }
+       }
+
        return 0;
 }
 
@@ -757,28 +777,18 @@ static int uvc_init_video_isoc(struct uv
 {
        struct urb *urb;
        unsigned int npackets, i, j;
-       __u16 psize;
-       __u32 size;
-
-       /* Compute the number of isochronous packets to allocate by dividing
-        * the maximum video frame size by the packet size. Limit the result
-        * to UVC_MAX_ISO_PACKETS.
-        */
+       u16 psize;
+       u32 size;
+
        psize = le16_to_cpu(ep->desc.wMaxPacketSize);
        psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3));
-
        size = video->streaming->ctrl.dwMaxVideoFrameSize;
-       if (size > UVC_MAX_FRAME_SIZE)
-               return -EINVAL;
-
-       npackets = DIV_ROUND_UP(size, psize);
-       if (npackets > UVC_MAX_ISO_PACKETS)
-               npackets = UVC_MAX_ISO_PACKETS;
+
+       npackets = uvc_alloc_urb_buffers(video, size, psize, gfp_flags);
+       if (npackets == 0)
+               return -ENOMEM;
 
        size = npackets * psize;
-
-       if (uvc_alloc_urb_buffers(video, size) < 0)
-               return -ENOMEM;
 
        for (i = 0; i < UVC_URBS; ++i) {
                urb = usb_alloc_urb(npackets, gfp_flags);
@@ -818,24 +828,19 @@ static int uvc_init_video_bulk(struct uv
        struct usb_host_endpoint *ep, gfp_t gfp_flags)
 {
        struct urb *urb;
-       unsigned int pipe, i;
-       __u16 psize;
-       __u32 size;
-
-       /* Compute the bulk URB size. Some devices set the maximum payload
-        * size to a value too high for memory-constrained devices. We must
-        * then transfer the payload accross multiple URBs. To be consistant
-        * with isochronous mode, allocate maximum UVC_MAX_ISO_PACKETS per bulk
-        * URB.
-        */
+       unsigned int npackets, pipe, i;
+       u16 psize;
+       u32 size;
+
        psize = le16_to_cpu(ep->desc.wMaxPacketSize) & 0x07ff;
        size = video->streaming->ctrl.dwMaxPayloadTransferSize;
        video->bulk.max_payload_size = size;
-       if (size > psize * UVC_MAX_ISO_PACKETS)
-               size = psize * UVC_MAX_ISO_PACKETS;
-
-       if (uvc_alloc_urb_buffers(video, size) < 0)
+
+       npackets = uvc_alloc_urb_buffers(video, size, psize, gfp_flags);
+       if (npackets == 0)
                return -ENOMEM;
+
+       size = npackets * psize;
 
        if (usb_endpoint_dir_in(&ep->desc))
                pipe = usb_rcvbulkpipe(video->dev->udev,
diff -r 843faef8fd17 -r 080861af82f1 linux/drivers/media/video/uvc/uvcvideo.h
--- a/linux/drivers/media/video/uvc/uvcvideo.h  Wed Jan 14 16:49:11 2009 +0100
+++ b/linux/drivers/media/video/uvc/uvcvideo.h  Sun Jan 18 21:46:30 2009 +0100
@@ -297,10 +297,8 @@ struct uvc_xu_control {
 
 /* Number of isochronous URBs. */
 #define UVC_URBS               5
-/* Maximum number of packets per isochronous URB. */
-#define UVC_MAX_ISO_PACKETS    40
-/* Maximum frame size in bytes, for sanity checking. */
-#define UVC_MAX_FRAME_SIZE     (16*1024*1024)
+/* Maximum number of packets per URB. */
+#define UVC_MAX_PACKETS                32
 /* Maximum number of video buffers. */
 #define UVC_MAX_VIDEO_BUFFERS  32
 /* Maximum status buffer size in bytes of interrupt URB. */


---

Patch is available at: 
http://linuxtv.org/hg/v4l-dvb/rev/080861af82f14c0197104ce664c12079ace23fff

_______________________________________________
linuxtv-commits mailing list
linuxtv-commits@linuxtv.org
http://www.linuxtv.org/cgi-bin/mailman/listinfo/linuxtv-commits

Reply via email to