diff options
author | Laurent Pinchart <laurent.pinchart@skynet.be> | 2008-07-03 23:36:21 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@infradead.org> | 2008-07-20 06:17:45 -0400 |
commit | e01117c81676dc9897f567e32cdc13a26e85280b (patch) | |
tree | 371bc23453782045f5236daaf891110b0337f013 /drivers/media/video | |
parent | 291358785cde5536d98a4f3cae77efd8ca626486 (diff) |
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: Laurent Pinchart <laurent.pinchart@skynet.be>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'drivers/media/video')
-rw-r--r-- | drivers/media/video/uvc/uvc_video.c | 96 | ||||
-rw-r--r-- | drivers/media/video/uvc/uvcvideo.h | 2 |
2 files changed, 66 insertions, 32 deletions
diff --git a/drivers/media/video/uvc/uvc_video.c b/drivers/media/video/uvc/uvc_video.c index 8eb5748c446e..817af2e36362 100644 --- a/drivers/media/video/uvc/uvc_video.c +++ b/drivers/media/video/uvc/uvc_video.c | |||
@@ -554,9 +554,56 @@ static void uvc_video_complete(struct urb *urb) | |||
554 | } | 554 | } |
555 | 555 | ||
556 | /* | 556 | /* |
557 | * Free transfer buffers. | ||
558 | */ | ||
559 | static void uvc_free_urb_buffers(struct uvc_video_device *video) | ||
560 | { | ||
561 | unsigned int i; | ||
562 | |||
563 | for (i = 0; i < UVC_URBS; ++i) { | ||
564 | if (video->urb_buffer[i]) { | ||
565 | usb_buffer_free(video->dev->udev, video->urb_size, | ||
566 | video->urb_buffer[i], video->urb_dma[i]); | ||
567 | video->urb_buffer[i] = NULL; | ||
568 | } | ||
569 | } | ||
570 | |||
571 | video->urb_size = 0; | ||
572 | } | ||
573 | |||
574 | /* | ||
575 | * Allocate transfer buffers. This function can be called with buffers | ||
576 | * already allocated when resuming from suspend, in which case it will | ||
577 | * return without touching the buffers. | ||
578 | * | ||
579 | * Return 0 on success or -ENOMEM when out of memory. | ||
580 | */ | ||
581 | static int uvc_alloc_urb_buffers(struct uvc_video_device *video, | ||
582 | unsigned int size) | ||
583 | { | ||
584 | unsigned int i; | ||
585 | |||
586 | /* Buffers are already allocated, bail out. */ | ||
587 | if (video->urb_size) | ||
588 | return 0; | ||
589 | |||
590 | for (i = 0; i < UVC_URBS; ++i) { | ||
591 | video->urb_buffer[i] = usb_buffer_alloc(video->dev->udev, | ||
592 | size, GFP_KERNEL, &video->urb_dma[i]); | ||
593 | if (video->urb_buffer[i] == NULL) { | ||
594 | uvc_free_urb_buffers(video); | ||
595 | return -ENOMEM; | ||
596 | } | ||
597 | } | ||
598 | |||
599 | video->urb_size = size; | ||
600 | return 0; | ||
601 | } | ||
602 | |||
603 | /* | ||
557 | * Uninitialize isochronous/bulk URBs and free transfer buffers. | 604 | * Uninitialize isochronous/bulk URBs and free transfer buffers. |
558 | */ | 605 | */ |
559 | static void uvc_uninit_video(struct uvc_video_device *video) | 606 | static void uvc_uninit_video(struct uvc_video_device *video, int free_buffers) |
560 | { | 607 | { |
561 | struct urb *urb; | 608 | struct urb *urb; |
562 | unsigned int i; | 609 | unsigned int i; |
@@ -566,19 +613,12 @@ static void uvc_uninit_video(struct uvc_video_device *video) | |||
566 | continue; | 613 | continue; |
567 | 614 | ||
568 | usb_kill_urb(urb); | 615 | usb_kill_urb(urb); |
569 | /* urb->transfer_buffer_length is not touched by USB core, so | ||
570 | * we can use it here as the buffer length. | ||
571 | */ | ||
572 | if (video->urb_buffer[i]) { | ||
573 | usb_buffer_free(video->dev->udev, | ||
574 | urb->transfer_buffer_length, | ||
575 | video->urb_buffer[i], urb->transfer_dma); | ||
576 | video->urb_buffer[i] = NULL; | ||
577 | } | ||
578 | |||
579 | usb_free_urb(urb); | 616 | usb_free_urb(urb); |
580 | video->urb[i] = NULL; | 617 | video->urb[i] = NULL; |
581 | } | 618 | } |
619 | |||
620 | if (free_buffers) | ||
621 | uvc_free_urb_buffers(video); | ||
582 | } | 622 | } |
583 | 623 | ||
584 | /* | 624 | /* |
@@ -610,18 +650,13 @@ static int uvc_init_video_isoc(struct uvc_video_device *video, | |||
610 | 650 | ||
611 | size = npackets * psize; | 651 | size = npackets * psize; |
612 | 652 | ||
653 | if (uvc_alloc_urb_buffers(video, size) < 0) | ||
654 | return -ENOMEM; | ||
655 | |||
613 | for (i = 0; i < UVC_URBS; ++i) { | 656 | for (i = 0; i < UVC_URBS; ++i) { |
614 | urb = usb_alloc_urb(npackets, gfp_flags); | 657 | urb = usb_alloc_urb(npackets, gfp_flags); |
615 | if (urb == NULL) { | 658 | if (urb == NULL) { |
616 | uvc_uninit_video(video); | 659 | uvc_uninit_video(video, 1); |
617 | return -ENOMEM; | ||
618 | } | ||
619 | |||
620 | video->urb_buffer[i] = usb_buffer_alloc(video->dev->udev, | ||
621 | size, gfp_flags, &urb->transfer_dma); | ||
622 | if (video->urb_buffer[i] == NULL) { | ||
623 | usb_free_urb(urb); | ||
624 | uvc_uninit_video(video); | ||
625 | return -ENOMEM; | 660 | return -ENOMEM; |
626 | } | 661 | } |
627 | 662 | ||
@@ -632,6 +667,7 @@ static int uvc_init_video_isoc(struct uvc_video_device *video, | |||
632 | urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; | 667 | urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; |
633 | urb->interval = ep->desc.bInterval; | 668 | urb->interval = ep->desc.bInterval; |
634 | urb->transfer_buffer = video->urb_buffer[i]; | 669 | urb->transfer_buffer = video->urb_buffer[i]; |
670 | urb->transfer_dma = video->urb_dma[i]; | ||
635 | urb->complete = uvc_video_complete; | 671 | urb->complete = uvc_video_complete; |
636 | urb->number_of_packets = npackets; | 672 | urb->number_of_packets = npackets; |
637 | urb->transfer_buffer_length = size; | 673 | urb->transfer_buffer_length = size; |
@@ -671,20 +707,15 @@ static int uvc_init_video_bulk(struct uvc_video_device *video, | |||
671 | if (size > psize * UVC_MAX_ISO_PACKETS) | 707 | if (size > psize * UVC_MAX_ISO_PACKETS) |
672 | size = psize * UVC_MAX_ISO_PACKETS; | 708 | size = psize * UVC_MAX_ISO_PACKETS; |
673 | 709 | ||
710 | if (uvc_alloc_urb_buffers(video, size) < 0) | ||
711 | return -ENOMEM; | ||
712 | |||
674 | pipe = usb_rcvbulkpipe(video->dev->udev, ep->desc.bEndpointAddress); | 713 | pipe = usb_rcvbulkpipe(video->dev->udev, ep->desc.bEndpointAddress); |
675 | 714 | ||
676 | for (i = 0; i < UVC_URBS; ++i) { | 715 | for (i = 0; i < UVC_URBS; ++i) { |
677 | urb = usb_alloc_urb(0, gfp_flags); | 716 | urb = usb_alloc_urb(0, gfp_flags); |
678 | if (urb == NULL) { | 717 | if (urb == NULL) { |
679 | uvc_uninit_video(video); | 718 | uvc_uninit_video(video, 1); |
680 | return -ENOMEM; | ||
681 | } | ||
682 | |||
683 | video->urb_buffer[i] = usb_buffer_alloc(video->dev->udev, | ||
684 | size, gfp_flags, &urb->transfer_dma); | ||
685 | if (video->urb_buffer[i] == NULL) { | ||
686 | usb_free_urb(urb); | ||
687 | uvc_uninit_video(video); | ||
688 | return -ENOMEM; | 719 | return -ENOMEM; |
689 | } | 720 | } |
690 | 721 | ||
@@ -692,6 +723,7 @@ static int uvc_init_video_bulk(struct uvc_video_device *video, | |||
692 | video->urb_buffer[i], size, uvc_video_complete, | 723 | video->urb_buffer[i], size, uvc_video_complete, |
693 | video); | 724 | video); |
694 | urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP; | 725 | urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP; |
726 | urb->transfer_dma = video->urb_dma[i]; | ||
695 | 727 | ||
696 | video->urb[i] = urb; | 728 | video->urb[i] = urb; |
697 | } | 729 | } |
@@ -766,7 +798,7 @@ static int uvc_init_video(struct uvc_video_device *video, gfp_t gfp_flags) | |||
766 | if ((ret = usb_submit_urb(video->urb[i], gfp_flags)) < 0) { | 798 | if ((ret = usb_submit_urb(video->urb[i], gfp_flags)) < 0) { |
767 | uvc_printk(KERN_ERR, "Failed to submit URB %u " | 799 | uvc_printk(KERN_ERR, "Failed to submit URB %u " |
768 | "(%d).\n", i, ret); | 800 | "(%d).\n", i, ret); |
769 | uvc_uninit_video(video); | 801 | uvc_uninit_video(video, 1); |
770 | return ret; | 802 | return ret; |
771 | } | 803 | } |
772 | } | 804 | } |
@@ -791,7 +823,7 @@ int uvc_video_suspend(struct uvc_video_device *video) | |||
791 | return 0; | 823 | return 0; |
792 | 824 | ||
793 | video->frozen = 1; | 825 | video->frozen = 1; |
794 | uvc_uninit_video(video); | 826 | uvc_uninit_video(video, 0); |
795 | usb_set_interface(video->dev->udev, video->streaming->intfnum, 0); | 827 | usb_set_interface(video->dev->udev, video->streaming->intfnum, 0); |
796 | return 0; | 828 | return 0; |
797 | } | 829 | } |
@@ -920,7 +952,7 @@ int uvc_video_enable(struct uvc_video_device *video, int enable) | |||
920 | int ret; | 952 | int ret; |
921 | 953 | ||
922 | if (!enable) { | 954 | if (!enable) { |
923 | uvc_uninit_video(video); | 955 | uvc_uninit_video(video, 1); |
924 | usb_set_interface(video->dev->udev, | 956 | usb_set_interface(video->dev->udev, |
925 | video->streaming->intfnum, 0); | 957 | video->streaming->intfnum, 0); |
926 | uvc_queue_enable(&video->queue, 0); | 958 | uvc_queue_enable(&video->queue, 0); |
diff --git a/drivers/media/video/uvc/uvcvideo.h b/drivers/media/video/uvc/uvcvideo.h index a995a780db1c..2444b8a9d2a0 100644 --- a/drivers/media/video/uvc/uvcvideo.h +++ b/drivers/media/video/uvc/uvcvideo.h | |||
@@ -602,6 +602,8 @@ struct uvc_video_device { | |||
602 | 602 | ||
603 | struct urb *urb[UVC_URBS]; | 603 | struct urb *urb[UVC_URBS]; |
604 | char *urb_buffer[UVC_URBS]; | 604 | char *urb_buffer[UVC_URBS]; |
605 | dma_addr_t urb_dma[UVC_URBS]; | ||
606 | unsigned int urb_size; | ||
605 | 607 | ||
606 | __u8 last_fid; | 608 | __u8 last_fid; |
607 | }; | 609 | }; |