Commit efdc8a95 authored by Laurent Pinchart's avatar Laurent Pinchart Committed by Mauro Carvalho Chehab

V4L/DVB (10295): 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.
Tested-by: default avatarJohannes Berg <johannes@sipsolutions.net>
Signed-off-by: default avatarLaurent Pinchart <laurent.pinchart@skynet.be>
Reviewed-by: default avatarJohannes Berg <johannes@sipsolutions.net>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent f61d1d8a
...@@ -699,27 +699,47 @@ static void uvc_free_urb_buffers(struct uvc_video_device *video) ...@@ -699,27 +699,47 @@ static void uvc_free_urb_buffers(struct uvc_video_device *video)
* already allocated when resuming from suspend, in which case it will * already allocated when resuming from suspend, in which case it will
* return without touching the buffers. * 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, 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; unsigned int i;
/* Buffers are already allocated, bail out. */ /* Buffers are already allocated, bail out. */
if (video->urb_size) if (video->urb_size)
return 0; return 0;
for (i = 0; i < UVC_URBS; ++i) { /* Compute the number of packets. Bulk endpoints might transfer UVC
video->urb_buffer[i] = usb_buffer_alloc(video->dev->udev, * payloads accross multiple URBs.
size, GFP_KERNEL, &video->urb_dma[i]); */
if (video->urb_buffer[i] == NULL) { npackets = DIV_ROUND_UP(size, psize);
uvc_free_urb_buffers(video); if (npackets > UVC_MAX_PACKETS)
return -ENOMEM; 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;
} }
} }
video->urb_size = size;
return 0; return 0;
} }
...@@ -753,29 +773,19 @@ static int uvc_init_video_isoc(struct uvc_video_device *video, ...@@ -753,29 +773,19 @@ static int uvc_init_video_isoc(struct uvc_video_device *video,
{ {
struct urb *urb; struct urb *urb;
unsigned int npackets, i, j; unsigned int npackets, i, j;
__u16 psize; u16 psize;
__u32 size; 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.
*/
psize = le16_to_cpu(ep->desc.wMaxPacketSize); psize = le16_to_cpu(ep->desc.wMaxPacketSize);
psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3)); psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3));
size = video->streaming->ctrl.dwMaxVideoFrameSize; size = video->streaming->ctrl.dwMaxVideoFrameSize;
if (size > UVC_MAX_FRAME_SIZE)
return -EINVAL;
npackets = DIV_ROUND_UP(size, psize); npackets = uvc_alloc_urb_buffers(video, size, psize, gfp_flags);
if (npackets > UVC_MAX_ISO_PACKETS) if (npackets == 0)
npackets = UVC_MAX_ISO_PACKETS; return -ENOMEM;
size = npackets * psize; size = npackets * psize;
if (uvc_alloc_urb_buffers(video, size) < 0)
return -ENOMEM;
for (i = 0; i < UVC_URBS; ++i) { for (i = 0; i < UVC_URBS; ++i) {
urb = usb_alloc_urb(npackets, gfp_flags); urb = usb_alloc_urb(npackets, gfp_flags);
if (urb == NULL) { if (urb == NULL) {
...@@ -814,25 +824,20 @@ static int uvc_init_video_bulk(struct uvc_video_device *video, ...@@ -814,25 +824,20 @@ static int uvc_init_video_bulk(struct uvc_video_device *video,
struct usb_host_endpoint *ep, gfp_t gfp_flags) struct usb_host_endpoint *ep, gfp_t gfp_flags)
{ {
struct urb *urb; struct urb *urb;
unsigned int pipe, i; unsigned int npackets, pipe, i;
__u16 psize; u16 psize;
__u32 size; 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.
*/
psize = le16_to_cpu(ep->desc.wMaxPacketSize) & 0x07ff; psize = le16_to_cpu(ep->desc.wMaxPacketSize) & 0x07ff;
size = video->streaming->ctrl.dwMaxPayloadTransferSize; size = video->streaming->ctrl.dwMaxPayloadTransferSize;
video->bulk.max_payload_size = size; 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; return -ENOMEM;
size = npackets * psize;
if (usb_endpoint_dir_in(&ep->desc)) if (usb_endpoint_dir_in(&ep->desc))
pipe = usb_rcvbulkpipe(video->dev->udev, pipe = usb_rcvbulkpipe(video->dev->udev,
ep->desc.bEndpointAddress); ep->desc.bEndpointAddress);
......
...@@ -296,10 +296,8 @@ struct uvc_xu_control { ...@@ -296,10 +296,8 @@ struct uvc_xu_control {
/* Number of isochronous URBs. */ /* Number of isochronous URBs. */
#define UVC_URBS 5 #define UVC_URBS 5
/* Maximum number of packets per isochronous URB. */ /* Maximum number of packets per URB. */
#define UVC_MAX_ISO_PACKETS 40 #define UVC_MAX_PACKETS 32
/* Maximum frame size in bytes, for sanity checking. */
#define UVC_MAX_FRAME_SIZE (16*1024*1024)
/* Maximum number of video buffers. */ /* Maximum number of video buffers. */
#define UVC_MAX_VIDEO_BUFFERS 32 #define UVC_MAX_VIDEO_BUFFERS 32
/* Maximum status buffer size in bytes of interrupt URB. */ /* Maximum status buffer size in bytes of interrupt URB. */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment