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

V4L/DVB (8209): uvcvideo: Don't free URB buffers on suspend.

All submitted URBs must be killed at suspend time, but URB buffers don't have
to be freed. Avoiding a free on suspend/reallocate on resume lowers the presure
on system memory.
Signed-off-by: default avatarLaurent Pinchart <laurent.pinchart@skynet.be>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@infradead.org>
parent 29135878
...@@ -553,10 +553,57 @@ static void uvc_video_complete(struct urb *urb) ...@@ -553,10 +553,57 @@ static void uvc_video_complete(struct urb *urb)
} }
} }
/*
* Free transfer buffers.
*/
static void uvc_free_urb_buffers(struct uvc_video_device *video)
{
unsigned int i;
for (i = 0; i < UVC_URBS; ++i) {
if (video->urb_buffer[i]) {
usb_buffer_free(video->dev->udev, video->urb_size,
video->urb_buffer[i], video->urb_dma[i]);
video->urb_buffer[i] = NULL;
}
}
video->urb_size = 0;
}
/*
* Allocate transfer buffers. This function can be called with buffers
* 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.
*/
static int uvc_alloc_urb_buffers(struct uvc_video_device *video,
unsigned int size)
{
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;
return 0;
}
/* /*
* Uninitialize isochronous/bulk URBs and free transfer buffers. * Uninitialize isochronous/bulk URBs and free transfer buffers.
*/ */
static void uvc_uninit_video(struct uvc_video_device *video) static void uvc_uninit_video(struct uvc_video_device *video, int free_buffers)
{ {
struct urb *urb; struct urb *urb;
unsigned int i; unsigned int i;
...@@ -566,19 +613,12 @@ static void uvc_uninit_video(struct uvc_video_device *video) ...@@ -566,19 +613,12 @@ static void uvc_uninit_video(struct uvc_video_device *video)
continue; continue;
usb_kill_urb(urb); usb_kill_urb(urb);
/* urb->transfer_buffer_length is not touched by USB core, so
* we can use it here as the buffer length.
*/
if (video->urb_buffer[i]) {
usb_buffer_free(video->dev->udev,
urb->transfer_buffer_length,
video->urb_buffer[i], urb->transfer_dma);
video->urb_buffer[i] = NULL;
}
usb_free_urb(urb); usb_free_urb(urb);
video->urb[i] = NULL; video->urb[i] = NULL;
} }
if (free_buffers)
uvc_free_urb_buffers(video);
} }
/* /*
...@@ -610,18 +650,13 @@ static int uvc_init_video_isoc(struct uvc_video_device *video, ...@@ -610,18 +650,13 @@ static int uvc_init_video_isoc(struct uvc_video_device *video,
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) {
uvc_uninit_video(video); uvc_uninit_video(video, 1);
return -ENOMEM;
}
video->urb_buffer[i] = usb_buffer_alloc(video->dev->udev,
size, gfp_flags, &urb->transfer_dma);
if (video->urb_buffer[i] == NULL) {
usb_free_urb(urb);
uvc_uninit_video(video);
return -ENOMEM; return -ENOMEM;
} }
...@@ -632,6 +667,7 @@ static int uvc_init_video_isoc(struct uvc_video_device *video, ...@@ -632,6 +667,7 @@ static int uvc_init_video_isoc(struct uvc_video_device *video,
urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
urb->interval = ep->desc.bInterval; urb->interval = ep->desc.bInterval;
urb->transfer_buffer = video->urb_buffer[i]; urb->transfer_buffer = video->urb_buffer[i];
urb->transfer_dma = video->urb_dma[i];
urb->complete = uvc_video_complete; urb->complete = uvc_video_complete;
urb->number_of_packets = npackets; urb->number_of_packets = npackets;
urb->transfer_buffer_length = size; urb->transfer_buffer_length = size;
...@@ -671,20 +707,15 @@ static int uvc_init_video_bulk(struct uvc_video_device *video, ...@@ -671,20 +707,15 @@ static int uvc_init_video_bulk(struct uvc_video_device *video,
if (size > psize * UVC_MAX_ISO_PACKETS) if (size > psize * UVC_MAX_ISO_PACKETS)
size = psize * UVC_MAX_ISO_PACKETS; size = psize * UVC_MAX_ISO_PACKETS;
if (uvc_alloc_urb_buffers(video, size) < 0)
return -ENOMEM;
pipe = usb_rcvbulkpipe(video->dev->udev, ep->desc.bEndpointAddress); pipe = usb_rcvbulkpipe(video->dev->udev, ep->desc.bEndpointAddress);
for (i = 0; i < UVC_URBS; ++i) { for (i = 0; i < UVC_URBS; ++i) {
urb = usb_alloc_urb(0, gfp_flags); urb = usb_alloc_urb(0, gfp_flags);
if (urb == NULL) { if (urb == NULL) {
uvc_uninit_video(video); uvc_uninit_video(video, 1);
return -ENOMEM;
}
video->urb_buffer[i] = usb_buffer_alloc(video->dev->udev,
size, gfp_flags, &urb->transfer_dma);
if (video->urb_buffer[i] == NULL) {
usb_free_urb(urb);
uvc_uninit_video(video);
return -ENOMEM; return -ENOMEM;
} }
...@@ -692,6 +723,7 @@ static int uvc_init_video_bulk(struct uvc_video_device *video, ...@@ -692,6 +723,7 @@ static int uvc_init_video_bulk(struct uvc_video_device *video,
video->urb_buffer[i], size, uvc_video_complete, video->urb_buffer[i], size, uvc_video_complete,
video); video);
urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP; urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
urb->transfer_dma = video->urb_dma[i];
video->urb[i] = urb; video->urb[i] = urb;
} }
...@@ -766,7 +798,7 @@ static int uvc_init_video(struct uvc_video_device *video, gfp_t gfp_flags) ...@@ -766,7 +798,7 @@ static int uvc_init_video(struct uvc_video_device *video, gfp_t gfp_flags)
if ((ret = usb_submit_urb(video->urb[i], gfp_flags)) < 0) { if ((ret = usb_submit_urb(video->urb[i], gfp_flags)) < 0) {
uvc_printk(KERN_ERR, "Failed to submit URB %u " uvc_printk(KERN_ERR, "Failed to submit URB %u "
"(%d).\n", i, ret); "(%d).\n", i, ret);
uvc_uninit_video(video); uvc_uninit_video(video, 1);
return ret; return ret;
} }
} }
...@@ -791,7 +823,7 @@ int uvc_video_suspend(struct uvc_video_device *video) ...@@ -791,7 +823,7 @@ int uvc_video_suspend(struct uvc_video_device *video)
return 0; return 0;
video->frozen = 1; video->frozen = 1;
uvc_uninit_video(video); uvc_uninit_video(video, 0);
usb_set_interface(video->dev->udev, video->streaming->intfnum, 0); usb_set_interface(video->dev->udev, video->streaming->intfnum, 0);
return 0; return 0;
} }
...@@ -920,7 +952,7 @@ int uvc_video_enable(struct uvc_video_device *video, int enable) ...@@ -920,7 +952,7 @@ int uvc_video_enable(struct uvc_video_device *video, int enable)
int ret; int ret;
if (!enable) { if (!enable) {
uvc_uninit_video(video); uvc_uninit_video(video, 1);
usb_set_interface(video->dev->udev, usb_set_interface(video->dev->udev,
video->streaming->intfnum, 0); video->streaming->intfnum, 0);
uvc_queue_enable(&video->queue, 0); uvc_queue_enable(&video->queue, 0);
......
...@@ -602,6 +602,8 @@ struct uvc_video_device { ...@@ -602,6 +602,8 @@ struct uvc_video_device {
struct urb *urb[UVC_URBS]; struct urb *urb[UVC_URBS];
char *urb_buffer[UVC_URBS]; char *urb_buffer[UVC_URBS];
dma_addr_t urb_dma[UVC_URBS];
unsigned int urb_size;
__u8 last_fid; __u8 last_fid;
}; };
......
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