From patchwork Tue Nov 6 21:27:12 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kieran Bingham X-Patchwork-Id: 10671415 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id C1A7914E2 for ; Tue, 6 Nov 2018 21:27:31 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id B22242AF66 for ; Tue, 6 Nov 2018 21:27:31 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id A62062AF6E; Tue, 6 Nov 2018 21:27:31 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id F3E6A2AF69 for ; Tue, 6 Nov 2018 21:27:30 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726507AbeKGGym (ORCPT ); Wed, 7 Nov 2018 01:54:42 -0500 Received: from perceval.ideasonboard.com ([213.167.242.64]:55636 "EHLO perceval.ideasonboard.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726463AbeKGGyl (ORCPT ); Wed, 7 Nov 2018 01:54:41 -0500 Received: from localhost.localdomain (cpc89242-aztw30-2-0-cust488.18-1.cable.virginm.net [86.31.129.233]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 22C3658D; Tue, 6 Nov 2018 22:27:26 +0100 (CET) From: Kieran Bingham To: Laurent Pinchart , linux-media@vger.kernel.org Cc: Guennadi Liakhovetski , Olivier BRAUN , Troy Kisky , Randy Dunlap , Philipp Zabel , Ezequiel Garcia , Kieran Bingham Subject: [PATCH v5 1/9] media: uvcvideo: Refactor URB descriptors Date: Tue, 6 Nov 2018 21:27:12 +0000 Message-Id: X-Mailer: git-send-email 2.17.1 In-Reply-To: References: In-Reply-To: References: Sender: linux-media-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Kieran Bingham We currently store three separate arrays for each URB reference we hold. Objectify the data needed to track URBs into a single uvc_urb structure, allowing better object management and tracking of the URB. All accesses to the data pointers through stream, are converted to use a uvc_urb pointer for consistency. Signed-off-by: Kieran Bingham Reviewed-by: Laurent Pinchart --- v2: - Re-describe URB context structure - Re-name uvc_urb->{urb_buffer,urb_dma}{buffer,dma} v3: - No change v4: - Rebase on top of linux-media/master (v4.16-rc4, metadata additions) drivers/media/usb/uvc/uvc_video.c | 49 +++++++++++++++++++------------- drivers/media/usb/uvc/uvcvideo.h | 18 ++++++++++-- 2 files changed, 45 insertions(+), 22 deletions(-) diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c index 86a99f461fd8..113881bed2a4 100644 --- a/drivers/media/usb/uvc/uvc_video.c +++ b/drivers/media/usb/uvc/uvc_video.c @@ -1506,14 +1506,16 @@ static void uvc_free_urb_buffers(struct uvc_streaming *stream) unsigned int i; for (i = 0; i < UVC_URBS; ++i) { - if (stream->urb_buffer[i]) { + struct uvc_urb *uvc_urb = &stream->uvc_urb[i]; + + if (uvc_urb->buffer) { #ifndef CONFIG_DMA_NONCOHERENT usb_free_coherent(stream->dev->udev, stream->urb_size, - stream->urb_buffer[i], stream->urb_dma[i]); + uvc_urb->buffer, uvc_urb->dma); #else - kfree(stream->urb_buffer[i]); + kfree(uvc_urb->buffer); #endif - stream->urb_buffer[i] = NULL; + uvc_urb->buffer = NULL; } } @@ -1551,16 +1553,18 @@ static int uvc_alloc_urb_buffers(struct uvc_streaming *stream, /* Retry allocations until one succeed. */ for (; npackets > 1; npackets /= 2) { for (i = 0; i < UVC_URBS; ++i) { + struct uvc_urb *uvc_urb = &stream->uvc_urb[i]; + stream->urb_size = psize * npackets; #ifndef CONFIG_DMA_NONCOHERENT - stream->urb_buffer[i] = usb_alloc_coherent( + uvc_urb->buffer = usb_alloc_coherent( stream->dev->udev, stream->urb_size, - gfp_flags | __GFP_NOWARN, &stream->urb_dma[i]); + gfp_flags | __GFP_NOWARN, &uvc_urb->dma); #else - stream->urb_buffer[i] = + uvc_urb->buffer = kmalloc(stream->urb_size, gfp_flags | __GFP_NOWARN); #endif - if (!stream->urb_buffer[i]) { + if (!uvc_urb->buffer) { uvc_free_urb_buffers(stream); break; } @@ -1590,13 +1594,15 @@ static void uvc_uninit_video(struct uvc_streaming *stream, int free_buffers) uvc_video_stats_stop(stream); for (i = 0; i < UVC_URBS; ++i) { - urb = stream->urb[i]; + struct uvc_urb *uvc_urb = &stream->uvc_urb[i]; + + urb = uvc_urb->urb; if (urb == NULL) continue; usb_kill_urb(urb); usb_free_urb(urb); - stream->urb[i] = NULL; + uvc_urb->urb = NULL; } if (free_buffers) @@ -1651,6 +1657,8 @@ static int uvc_init_video_isoc(struct uvc_streaming *stream, size = npackets * psize; for (i = 0; i < UVC_URBS; ++i) { + struct uvc_urb *uvc_urb = &stream->uvc_urb[i]; + urb = usb_alloc_urb(npackets, gfp_flags); if (urb == NULL) { uvc_uninit_video(stream, 1); @@ -1663,12 +1671,12 @@ static int uvc_init_video_isoc(struct uvc_streaming *stream, 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]; + urb->transfer_dma = uvc_urb->dma; #else urb->transfer_flags = URB_ISO_ASAP; #endif urb->interval = ep->desc.bInterval; - urb->transfer_buffer = stream->urb_buffer[i]; + urb->transfer_buffer = uvc_urb->buffer; urb->complete = uvc_video_complete; urb->number_of_packets = npackets; urb->transfer_buffer_length = size; @@ -1678,7 +1686,7 @@ static int uvc_init_video_isoc(struct uvc_streaming *stream, urb->iso_frame_desc[j].length = psize; } - stream->urb[i] = urb; + uvc_urb->urb = urb; } return 0; @@ -1717,21 +1725,22 @@ static int uvc_init_video_bulk(struct uvc_streaming *stream, size = 0; for (i = 0; i < UVC_URBS; ++i) { + struct uvc_urb *uvc_urb = &stream->uvc_urb[i]; + urb = usb_alloc_urb(0, gfp_flags); if (urb == NULL) { uvc_uninit_video(stream, 1); return -ENOMEM; } - usb_fill_bulk_urb(urb, stream->dev->udev, pipe, - stream->urb_buffer[i], size, uvc_video_complete, - stream); + usb_fill_bulk_urb(urb, stream->dev->udev, pipe, uvc_urb->buffer, + size, uvc_video_complete, stream); #ifndef CONFIG_DMA_NONCOHERENT urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP; - urb->transfer_dma = stream->urb_dma[i]; + urb->transfer_dma = uvc_urb->dma; #endif - stream->urb[i] = urb; + uvc_urb->urb = urb; } return 0; @@ -1822,7 +1831,9 @@ static int uvc_init_video(struct uvc_streaming *stream, gfp_t gfp_flags) /* Submit the URBs. */ for (i = 0; i < UVC_URBS; ++i) { - ret = usb_submit_urb(stream->urb[i], gfp_flags); + struct uvc_urb *uvc_urb = &stream->uvc_urb[i]; + + ret = usb_submit_urb(uvc_urb->urb, gfp_flags); if (ret < 0) { uvc_printk(KERN_ERR, "Failed to submit URB %u " "(%d).\n", i, ret); diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h index c0cbd833d0a4..29104b968f12 100644 --- a/drivers/media/usb/uvc/uvcvideo.h +++ b/drivers/media/usb/uvc/uvcvideo.h @@ -487,6 +487,20 @@ struct uvc_stats_stream { #define UVC_METATADA_BUF_SIZE 1024 +/** + * struct uvc_urb - URB context management structure + * + * @urb: the URB described by this context structure + * @buffer: memory storage for the URB + * @dma: DMA coherent addressing for the urb_buffer + */ +struct uvc_urb { + struct urb *urb; + + char *buffer; + dma_addr_t dma; +}; + struct uvc_streaming { struct list_head list; struct uvc_device *dev; @@ -535,9 +549,7 @@ struct uvc_streaming { u32 max_payload_size; } bulk; - struct urb *urb[UVC_URBS]; - char *urb_buffer[UVC_URBS]; - dma_addr_t urb_dma[UVC_URBS]; + struct uvc_urb uvc_urb[UVC_URBS]; unsigned int urb_size; u32 sequence; From patchwork Tue Nov 6 21:27:13 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kieran Bingham X-Patchwork-Id: 10671417 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 2117318FD for ; Tue, 6 Nov 2018 21:27:32 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 129872AF66 for ; Tue, 6 Nov 2018 21:27:32 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 0665C2AF69; Tue, 6 Nov 2018 21:27:32 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 6790E2AF76 for ; Tue, 6 Nov 2018 21:27:31 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726533AbeKGGym (ORCPT ); Wed, 7 Nov 2018 01:54:42 -0500 Received: from perceval.ideasonboard.com ([213.167.242.64]:55676 "EHLO perceval.ideasonboard.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725951AbeKGGym (ORCPT ); Wed, 7 Nov 2018 01:54:42 -0500 Received: from localhost.localdomain (cpc89242-aztw30-2-0-cust488.18-1.cable.virginm.net [86.31.129.233]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id A82CE58E; Tue, 6 Nov 2018 22:27:26 +0100 (CET) From: Kieran Bingham To: Laurent Pinchart , linux-media@vger.kernel.org Cc: Guennadi Liakhovetski , Olivier BRAUN , Troy Kisky , Randy Dunlap , Philipp Zabel , Ezequiel Garcia , Kieran Bingham Subject: [PATCH v5 2/9] media: uvcvideo: Convert decode functions to use new context structure Date: Tue, 6 Nov 2018 21:27:13 +0000 Message-Id: <9209b70f2ae81a6d42382457ff1970cb63ef5c19.1541534872.git-series.kieran.bingham@ideasonboard.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: References: In-Reply-To: References: Sender: linux-media-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Kieran Bingham The URB completion handlers currently reference the stream context. Now that each URB has its own context structure, convert the decode (and one encode) functions to utilise this context for URB management. Signed-off-by: Kieran Bingham Reviewed-by: Laurent Pinchart --- v2: - fix checkpatch warning (pre-existing in code) v3: (none) v4: - Rebase on top of linux-media/master (v4.16-rc4, metadata additions) drivers/media/usb/uvc/uvc_isight.c | 6 ++++-- drivers/media/usb/uvc/uvc_video.c | 26 ++++++++++++++++++-------- drivers/media/usb/uvc/uvcvideo.h | 8 +++++--- 3 files changed, 27 insertions(+), 13 deletions(-) diff --git a/drivers/media/usb/uvc/uvc_isight.c b/drivers/media/usb/uvc/uvc_isight.c index 81e6f2187bfb..39a4e4482b23 100644 --- a/drivers/media/usb/uvc/uvc_isight.c +++ b/drivers/media/usb/uvc/uvc_isight.c @@ -99,9 +99,11 @@ static int isight_decode(struct uvc_video_queue *queue, struct uvc_buffer *buf, return 0; } -void uvc_video_decode_isight(struct urb *urb, struct uvc_streaming *stream, - struct uvc_buffer *buf, struct uvc_buffer *meta_buf) +void uvc_video_decode_isight(struct uvc_urb *uvc_urb, struct uvc_buffer *buf, + struct uvc_buffer *meta_buf) { + struct urb *urb = uvc_urb->urb; + struct uvc_streaming *stream = uvc_urb->stream; int ret, i; for (i = 0; i < urb->number_of_packets; ++i) { diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c index 113881bed2a4..6d4384695964 100644 --- a/drivers/media/usb/uvc/uvc_video.c +++ b/drivers/media/usb/uvc/uvc_video.c @@ -1291,9 +1291,11 @@ static void uvc_video_next_buffers(struct uvc_streaming *stream, *video_buf = uvc_queue_next_buffer(&stream->queue, *video_buf); } -static void uvc_video_decode_isoc(struct urb *urb, struct uvc_streaming *stream, +static void uvc_video_decode_isoc(struct uvc_urb *uvc_urb, struct uvc_buffer *buf, struct uvc_buffer *meta_buf) { + struct urb *urb = uvc_urb->urb; + struct uvc_streaming *stream = uvc_urb->stream; u8 *mem; int ret, i; @@ -1334,9 +1336,11 @@ static void uvc_video_decode_isoc(struct urb *urb, struct uvc_streaming *stream, } } -static void uvc_video_decode_bulk(struct urb *urb, struct uvc_streaming *stream, +static void uvc_video_decode_bulk(struct uvc_urb *uvc_urb, struct uvc_buffer *buf, struct uvc_buffer *meta_buf) { + struct urb *urb = uvc_urb->urb; + struct uvc_streaming *stream = uvc_urb->stream; u8 *mem; int len, ret; @@ -1402,9 +1406,12 @@ static void uvc_video_decode_bulk(struct urb *urb, struct uvc_streaming *stream, } } -static void uvc_video_encode_bulk(struct urb *urb, struct uvc_streaming *stream, +static void uvc_video_encode_bulk(struct uvc_urb *uvc_urb, struct uvc_buffer *buf, struct uvc_buffer *meta_buf) { + struct urb *urb = uvc_urb->urb; + struct uvc_streaming *stream = uvc_urb->stream; + u8 *mem = urb->transfer_buffer; int len = stream->urb_size, ret; @@ -1447,7 +1454,8 @@ static void uvc_video_encode_bulk(struct urb *urb, struct uvc_streaming *stream, static void uvc_video_complete(struct urb *urb) { - struct uvc_streaming *stream = urb->context; + struct uvc_urb *uvc_urb = urb->context; + struct uvc_streaming *stream = uvc_urb->stream; struct uvc_video_queue *queue = &stream->queue; struct uvc_video_queue *qmeta = &stream->meta.queue; struct vb2_queue *vb2_qmeta = stream->meta.vdev.queue; @@ -1490,7 +1498,7 @@ static void uvc_video_complete(struct urb *urb) spin_unlock_irqrestore(&qmeta->irqlock, flags); } - stream->decode(urb, stream, buf, buf_meta); + stream->decode(uvc_urb, buf, buf_meta); if ((ret = usb_submit_urb(urb, GFP_ATOMIC)) < 0) { uvc_printk(KERN_ERR, "Failed to resubmit video URB (%d).\n", @@ -1568,6 +1576,8 @@ static int uvc_alloc_urb_buffers(struct uvc_streaming *stream, uvc_free_urb_buffers(stream); break; } + + uvc_urb->stream = stream; } if (i == UVC_URBS) { @@ -1666,7 +1676,7 @@ static int uvc_init_video_isoc(struct uvc_streaming *stream, } urb->dev = stream->dev->udev; - urb->context = stream; + urb->context = uvc_urb; urb->pipe = usb_rcvisocpipe(stream->dev->udev, ep->desc.bEndpointAddress); #ifndef CONFIG_DMA_NONCOHERENT @@ -1733,8 +1743,8 @@ static int uvc_init_video_bulk(struct uvc_streaming *stream, return -ENOMEM; } - usb_fill_bulk_urb(urb, stream->dev->udev, pipe, uvc_urb->buffer, - size, uvc_video_complete, stream); + usb_fill_bulk_urb(urb, stream->dev->udev, pipe, uvc_urb->buffer, + size, uvc_video_complete, uvc_urb); #ifndef CONFIG_DMA_NONCOHERENT urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP; urb->transfer_dma = uvc_urb->dma; diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h index 29104b968f12..f7f8db6fc91a 100644 --- a/drivers/media/usb/uvc/uvcvideo.h +++ b/drivers/media/usb/uvc/uvcvideo.h @@ -491,11 +491,13 @@ struct uvc_stats_stream { * struct uvc_urb - URB context management structure * * @urb: the URB described by this context structure + * @stream: UVC streaming context * @buffer: memory storage for the URB * @dma: DMA coherent addressing for the urb_buffer */ struct uvc_urb { struct urb *urb; + struct uvc_streaming *stream; char *buffer; dma_addr_t dma; @@ -531,8 +533,8 @@ struct uvc_streaming { /* Buffers queue. */ unsigned int frozen : 1; struct uvc_video_queue queue; - void (*decode) (struct urb *urb, struct uvc_streaming *video, - struct uvc_buffer *buf, struct uvc_buffer *meta_buf); + void (*decode)(struct uvc_urb *uvc_urb, struct uvc_buffer *buf, + struct uvc_buffer *meta_buf); struct { struct video_device vdev; @@ -818,7 +820,7 @@ struct usb_host_endpoint *uvc_find_endpoint(struct usb_host_interface *alts, u8 epaddr); /* Quirks support */ -void uvc_video_decode_isight(struct urb *urb, struct uvc_streaming *stream, +void uvc_video_decode_isight(struct uvc_urb *uvc_urb, struct uvc_buffer *buf, struct uvc_buffer *meta_buf); From patchwork Tue Nov 6 21:27:14 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kieran Bingham X-Patchwork-Id: 10671419 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id D3CF114E2 for ; Tue, 6 Nov 2018 21:27:32 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id C44F52AF66 for ; Tue, 6 Nov 2018 21:27:32 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id B87B92AF6E; Tue, 6 Nov 2018 21:27:32 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 5061C2AF66 for ; Tue, 6 Nov 2018 21:27:32 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726558AbeKGGyn (ORCPT ); Wed, 7 Nov 2018 01:54:43 -0500 Received: from perceval.ideasonboard.com ([213.167.242.64]:55690 "EHLO perceval.ideasonboard.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726282AbeKGGyn (ORCPT ); Wed, 7 Nov 2018 01:54:43 -0500 Received: from localhost.localdomain (cpc89242-aztw30-2-0-cust488.18-1.cable.virginm.net [86.31.129.233]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 35DE458F; Tue, 6 Nov 2018 22:27:27 +0100 (CET) From: Kieran Bingham To: Laurent Pinchart , linux-media@vger.kernel.org Cc: Guennadi Liakhovetski , Olivier BRAUN , Troy Kisky , Randy Dunlap , Philipp Zabel , Ezequiel Garcia , Kieran Bingham Subject: [PATCH v5 3/9] media: uvcvideo: Protect queue internals with helper Date: Tue, 6 Nov 2018 21:27:14 +0000 Message-Id: X-Mailer: git-send-email 2.17.1 In-Reply-To: References: In-Reply-To: References: Sender: linux-media-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Kieran Bingham The URB completion operation obtains the current buffer by reading directly into the queue internal interface. Protect this queue abstraction by providing a helper uvc_queue_get_current_buffer() which can be used by both the decode task, and the uvc_queue_next_buffer() functions. Signed-off-by: Kieran Bingham Reviewed-by: Laurent Pinchart --- v2: - Fix coding style of conditional statements v3: - No change v4: - Rebase on top of linux-media/master (v4.16-rc4, metadata additions) drivers/media/usb/uvc/uvc_queue.c | 33 +++++++++++++++++++++++++++----- drivers/media/usb/uvc/uvc_video.c | 6 +----- drivers/media/usb/uvc/uvcvideo.h | 1 +- 3 files changed, 30 insertions(+), 10 deletions(-) diff --git a/drivers/media/usb/uvc/uvc_queue.c b/drivers/media/usb/uvc/uvc_queue.c index 8964e16f2b22..74f9483911d0 100644 --- a/drivers/media/usb/uvc/uvc_queue.c +++ b/drivers/media/usb/uvc/uvc_queue.c @@ -430,6 +430,33 @@ void uvc_queue_cancel(struct uvc_video_queue *queue, int disconnect) spin_unlock_irqrestore(&queue->irqlock, flags); } +/* + * uvc_queue_get_current_buffer: Obtain the current working output buffer + * + * Buffers may span multiple packets, and even URBs, therefore the active buffer + * remains on the queue until the EOF marker. + */ +static struct uvc_buffer * +__uvc_queue_get_current_buffer(struct uvc_video_queue *queue) +{ + if (list_empty(&queue->irqqueue)) + return NULL; + + return list_first_entry(&queue->irqqueue, struct uvc_buffer, queue); +} + +struct uvc_buffer *uvc_queue_get_current_buffer(struct uvc_video_queue *queue) +{ + struct uvc_buffer *nextbuf; + unsigned long flags; + + spin_lock_irqsave(&queue->irqlock, flags); + nextbuf = __uvc_queue_get_current_buffer(queue); + spin_unlock_irqrestore(&queue->irqlock, flags); + + return nextbuf; +} + struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue, struct uvc_buffer *buf) { @@ -446,11 +473,7 @@ struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue, spin_lock_irqsave(&queue->irqlock, flags); list_del(&buf->queue); - if (!list_empty(&queue->irqqueue)) - nextbuf = list_first_entry(&queue->irqqueue, struct uvc_buffer, - queue); - else - nextbuf = NULL; + nextbuf = __uvc_queue_get_current_buffer(queue); spin_unlock_irqrestore(&queue->irqlock, flags); buf->state = buf->error ? UVC_BUF_STATE_ERROR : UVC_BUF_STATE_DONE; diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c index 6d4384695964..7a7779e1b466 100644 --- a/drivers/media/usb/uvc/uvc_video.c +++ b/drivers/media/usb/uvc/uvc_video.c @@ -1484,11 +1484,7 @@ static void uvc_video_complete(struct urb *urb) return; } - spin_lock_irqsave(&queue->irqlock, flags); - if (!list_empty(&queue->irqqueue)) - buf = list_first_entry(&queue->irqqueue, struct uvc_buffer, - queue); - spin_unlock_irqrestore(&queue->irqlock, flags); + buf = uvc_queue_get_current_buffer(queue); if (vb2_qmeta) { spin_lock_irqsave(&qmeta->irqlock, flags); diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h index f7f8db6fc91a..bdb6d8daedab 100644 --- a/drivers/media/usb/uvc/uvcvideo.h +++ b/drivers/media/usb/uvc/uvcvideo.h @@ -725,6 +725,7 @@ int uvc_queue_streamoff(struct uvc_video_queue *queue, enum v4l2_buf_type type); void uvc_queue_cancel(struct uvc_video_queue *queue, int disconnect); struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue, struct uvc_buffer *buf); +struct uvc_buffer *uvc_queue_get_current_buffer(struct uvc_video_queue *queue); int uvc_queue_mmap(struct uvc_video_queue *queue, struct vm_area_struct *vma); __poll_t uvc_queue_poll(struct uvc_video_queue *queue, struct file *file, From patchwork Tue Nov 6 21:27:15 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kieran Bingham X-Patchwork-Id: 10671421 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 4766F1751 for ; Tue, 6 Nov 2018 21:27:33 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 39A162AF66 for ; Tue, 6 Nov 2018 21:27:33 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 2D7FD2AF69; Tue, 6 Nov 2018 21:27:33 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id D04242AF74 for ; Tue, 6 Nov 2018 21:27:32 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726611AbeKGGyo (ORCPT ); Wed, 7 Nov 2018 01:54:44 -0500 Received: from perceval.ideasonboard.com ([213.167.242.64]:55676 "EHLO perceval.ideasonboard.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726463AbeKGGyn (ORCPT ); Wed, 7 Nov 2018 01:54:43 -0500 Received: from localhost.localdomain (cpc89242-aztw30-2-0-cust488.18-1.cable.virginm.net [86.31.129.233]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id BBFCA590; Tue, 6 Nov 2018 22:27:27 +0100 (CET) From: Kieran Bingham To: Laurent Pinchart , linux-media@vger.kernel.org Cc: Guennadi Liakhovetski , Olivier BRAUN , Troy Kisky , Randy Dunlap , Philipp Zabel , Ezequiel Garcia , Kieran Bingham Subject: [PATCH v5 4/9] media: uvcvideo: queue: Simplify spin-lock usage Date: Tue, 6 Nov 2018 21:27:15 +0000 Message-Id: <210be9b2f38af75b3747415d0372f4f12b2bee19.1541534872.git-series.kieran.bingham@ideasonboard.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: References: In-Reply-To: References: Sender: linux-media-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Kieran Bingham Both uvc_start_streaming(), and uvc_stop_streaming() are called from userspace context, with interrupts enabled. As such, they do not need to save the IRQ state, and can use spin_lock_irq() and spin_unlock_irq() respectively. Signed-off-by: Kieran Bingham Reviewed-by: Laurent Pinchart --- v4: - Rebase to v4.16 (linux-media/master) v5: - Provide lockdep validation drivers/media/usb/uvc/uvc_queue.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/media/usb/uvc/uvc_queue.c b/drivers/media/usb/uvc/uvc_queue.c index 74f9483911d0..bebf2415d9de 100644 --- a/drivers/media/usb/uvc/uvc_queue.c +++ b/drivers/media/usb/uvc/uvc_queue.c @@ -169,18 +169,19 @@ static int uvc_start_streaming(struct vb2_queue *vq, unsigned int count) { struct uvc_video_queue *queue = vb2_get_drv_priv(vq); struct uvc_streaming *stream = uvc_queue_to_stream(queue); - unsigned long flags; int ret; + lockdep_assert_irqs_enabled(); + queue->buf_used = 0; ret = uvc_video_enable(stream, 1); if (ret == 0) return 0; - spin_lock_irqsave(&queue->irqlock, flags); + spin_lock_irq(&queue->irqlock); uvc_queue_return_buffers(queue, UVC_BUF_STATE_QUEUED); - spin_unlock_irqrestore(&queue->irqlock, flags); + spin_unlock_irq(&queue->irqlock); return ret; } @@ -188,14 +189,15 @@ static int uvc_start_streaming(struct vb2_queue *vq, unsigned int count) static void uvc_stop_streaming(struct vb2_queue *vq) { struct uvc_video_queue *queue = vb2_get_drv_priv(vq); - unsigned long flags; + + lockdep_assert_irqs_enabled(); if (vq->type != V4L2_BUF_TYPE_META_CAPTURE) uvc_video_enable(uvc_queue_to_stream(queue), 0); - spin_lock_irqsave(&queue->irqlock, flags); + spin_lock_irq(&queue->irqlock); uvc_queue_return_buffers(queue, UVC_BUF_STATE_ERROR); - spin_unlock_irqrestore(&queue->irqlock, flags); + spin_unlock_irq(&queue->irqlock); } static const struct vb2_ops uvc_queue_qops = { From patchwork Tue Nov 6 21:27:16 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kieran Bingham X-Patchwork-Id: 10671423 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 0E7061709 for ; Tue, 6 Nov 2018 21:27:35 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id F3AC82AF66 for ; Tue, 6 Nov 2018 21:27:34 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id E7CE12AF6E; Tue, 6 Nov 2018 21:27:34 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 75D592AF66 for ; Tue, 6 Nov 2018 21:27:34 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726671AbeKGGyp (ORCPT ); Wed, 7 Nov 2018 01:54:45 -0500 Received: from perceval.ideasonboard.com ([213.167.242.64]:55690 "EHLO perceval.ideasonboard.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726282AbeKGGyp (ORCPT ); Wed, 7 Nov 2018 01:54:45 -0500 Received: from localhost.localdomain (cpc89242-aztw30-2-0-cust488.18-1.cable.virginm.net [86.31.129.233]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 4A09C591; Tue, 6 Nov 2018 22:27:28 +0100 (CET) From: Kieran Bingham To: Laurent Pinchart , linux-media@vger.kernel.org Cc: Guennadi Liakhovetski , Olivier BRAUN , Troy Kisky , Randy Dunlap , Philipp Zabel , Ezequiel Garcia , Kieran Bingham Subject: [PATCH v5 5/9] media: uvcvideo: queue: Support asynchronous buffer handling Date: Tue, 6 Nov 2018 21:27:16 +0000 Message-Id: X-Mailer: git-send-email 2.17.1 In-Reply-To: References: In-Reply-To: References: Sender: linux-media-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Kieran Bingham The buffer queue interface currently operates sequentially, processing buffers after they have fully completed. In preparation for supporting parallel tasks operating on the buffers, we will need to support buffers being processed on multiple CPUs. Adapt the uvc_queue_next_buffer() such that a reference count tracks the active use of the buffer, returning the buffer to the VB2 stack at completion. Signed-off-by: Kieran Bingham v5: - uvc_queue_requeue() -> uvc_queue_buffer_requeue() - Fix comment Reviewed-by: Laurent Pinchart --- drivers/media/usb/uvc/uvc_queue.c | 61 ++++++++++++++++++++++++++------ drivers/media/usb/uvc/uvcvideo.h | 4 ++- 2 files changed, 54 insertions(+), 11 deletions(-) diff --git a/drivers/media/usb/uvc/uvc_queue.c b/drivers/media/usb/uvc/uvc_queue.c index bebf2415d9de..cd8c03341de0 100644 --- a/drivers/media/usb/uvc/uvc_queue.c +++ b/drivers/media/usb/uvc/uvc_queue.c @@ -142,6 +142,7 @@ static void uvc_buffer_queue(struct vb2_buffer *vb) spin_lock_irqsave(&queue->irqlock, flags); if (likely(!(queue->flags & UVC_QUEUE_DISCONNECTED))) { + kref_init(&buf->ref); list_add_tail(&buf->queue, &queue->irqqueue); } else { /* If the device is disconnected return the buffer to userspace @@ -459,28 +460,66 @@ struct uvc_buffer *uvc_queue_get_current_buffer(struct uvc_video_queue *queue) return nextbuf; } -struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue, +/* + * uvc_queue_buffer_requeue: Requeue a buffer on our internal irqqueue + * + * Reuse a buffer through our internal queue without the need to 'prepare'. + * The buffer will be returned to userspace through the uvc_buffer_queue call if + * the device has been disconnected. + */ +static void uvc_queue_buffer_requeue(struct uvc_video_queue *queue, struct uvc_buffer *buf) { - struct uvc_buffer *nextbuf; - unsigned long flags; + buf->error = 0; + buf->state = UVC_BUF_STATE_QUEUED; + buf->bytesused = 0; + vb2_set_plane_payload(&buf->buf.vb2_buf, 0, 0); + + uvc_buffer_queue(&buf->buf.vb2_buf); +} + +static void uvc_queue_buffer_complete(struct kref *ref) +{ + struct uvc_buffer *buf = container_of(ref, struct uvc_buffer, ref); + struct vb2_buffer *vb = &buf->buf.vb2_buf; + struct uvc_video_queue *queue = vb2_get_drv_priv(vb->vb2_queue); if ((queue->flags & UVC_QUEUE_DROP_CORRUPTED) && buf->error) { - buf->error = 0; - buf->state = UVC_BUF_STATE_QUEUED; - buf->bytesused = 0; - vb2_set_plane_payload(&buf->buf.vb2_buf, 0, 0); - return buf; + uvc_queue_buffer_requeue(queue, buf); + return; } + buf->state = buf->error ? UVC_BUF_STATE_ERROR : UVC_BUF_STATE_DONE; + vb2_set_plane_payload(&buf->buf.vb2_buf, 0, buf->bytesused); + vb2_buffer_done(&buf->buf.vb2_buf, VB2_BUF_STATE_DONE); +} + +/* + * Release a reference on the buffer. Complete the buffer when the last + * reference is released. + */ +void uvc_queue_buffer_release(struct uvc_buffer *buf) +{ + kref_put(&buf->ref, uvc_queue_buffer_complete); +} + +/* + * Remove this buffer from the queue. Lifetime will persist while async actions + * are still running (if any), and uvc_queue_buffer_release will give the buffer + * back to VB2 when all users have completed. + */ +struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue, + struct uvc_buffer *buf) +{ + struct uvc_buffer *nextbuf; + unsigned long flags; + spin_lock_irqsave(&queue->irqlock, flags); list_del(&buf->queue); nextbuf = __uvc_queue_get_current_buffer(queue); spin_unlock_irqrestore(&queue->irqlock, flags); - buf->state = buf->error ? UVC_BUF_STATE_ERROR : UVC_BUF_STATE_DONE; - vb2_set_plane_payload(&buf->buf.vb2_buf, 0, buf->bytesused); - vb2_buffer_done(&buf->buf.vb2_buf, VB2_BUF_STATE_DONE); + uvc_queue_buffer_release(buf); return nextbuf; } diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h index bdb6d8daedab..1bc17da7f3d4 100644 --- a/drivers/media/usb/uvc/uvcvideo.h +++ b/drivers/media/usb/uvc/uvcvideo.h @@ -410,6 +410,9 @@ struct uvc_buffer { unsigned int bytesused; u32 pts; + + /* Asynchronous buffer handling. */ + struct kref ref; }; #define UVC_QUEUE_DISCONNECTED (1 << 0) @@ -726,6 +729,7 @@ void uvc_queue_cancel(struct uvc_video_queue *queue, int disconnect); struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue, struct uvc_buffer *buf); struct uvc_buffer *uvc_queue_get_current_buffer(struct uvc_video_queue *queue); +void uvc_queue_buffer_release(struct uvc_buffer *buf); int uvc_queue_mmap(struct uvc_video_queue *queue, struct vm_area_struct *vma); __poll_t uvc_queue_poll(struct uvc_video_queue *queue, struct file *file, From patchwork Tue Nov 6 21:27:17 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kieran Bingham X-Patchwork-Id: 10671425 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 320E01709 for ; Tue, 6 Nov 2018 21:27:36 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 22EF82AF66 for ; Tue, 6 Nov 2018 21:27:36 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 16FFF2AF74; Tue, 6 Nov 2018 21:27:36 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 3BB332AF66 for ; Tue, 6 Nov 2018 21:27:35 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727076AbeKGGyq (ORCPT ); Wed, 7 Nov 2018 01:54:46 -0500 Received: from perceval.ideasonboard.com ([213.167.242.64]:55676 "EHLO perceval.ideasonboard.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726463AbeKGGyp (ORCPT ); Wed, 7 Nov 2018 01:54:45 -0500 Received: from localhost.localdomain (cpc89242-aztw30-2-0-cust488.18-1.cable.virginm.net [86.31.129.233]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id CD7F8592; Tue, 6 Nov 2018 22:27:28 +0100 (CET) From: Kieran Bingham To: Laurent Pinchart , linux-media@vger.kernel.org Cc: Guennadi Liakhovetski , Olivier BRAUN , Troy Kisky , Randy Dunlap , Philipp Zabel , Ezequiel Garcia , Kieran Bingham Subject: [PATCH v5 6/9] media: uvcvideo: Move decode processing to process context Date: Tue, 6 Nov 2018 21:27:17 +0000 Message-Id: <926c5590f922810b52851415803c01e32ebeae7b.1541534872.git-series.kieran.bingham@ideasonboard.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: References: In-Reply-To: References: Sender: linux-media-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Kieran Bingham Newer high definition cameras, and cameras with multiple lenses such as the range of stereo-vision cameras now available have ever increasing data rates. The inclusion of a variable length packet header in URB packets mean that we must memcpy the frame data out to our destination 'manually'. This can result in data rates of up to 2 gigabits per second being processed. To improve efficiency, and maximise throughput, handle the URB decode processing through a work queue to move it from interrupt context, and allow multiple processors to work on URBs in parallel. Signed-off-by: Kieran Bingham Reviewed-by: Laurent Pinchart --- v2: - Lock full critical section of usb_submit_urb() v3: - Fix race on submitting uvc_video_decode_data_work() to work queue. - Rename uvc_decode_op -> uvc_copy_op (Generic to encode/decode) - Rename decodes -> copy_operations - Don't queue work if there is no async task - obtain copy op structure directly in uvc_video_decode_data() - uvc_video_decode_data_work() -> uvc_video_copy_data_work() v4: - Provide for_each_uvc_urb() - Simplify fix for shutdown race to flush queue before freeing URBs - Rebase to v4.16-rc4 (linux-media/master) adjusting for metadata conflicts. v5: - Rebase to media/v4.20-2 - Use GFP_KERNEL allocation in uvc_video_copy_data_work() - Fix function documentation for uvc_video_copy_data_work() - Add periods to the end of sentences - Rename 'decode' variable to 'op' in uvc_video_decode_data() - Move uvc_urb->async_operations initialisation to before use - Move async workqueue to match uvc_streaming lifetime instead of streamon/streamoff drivers/media/usb/uvc/uvc_driver.c | 2 +- drivers/media/usb/uvc/uvc_video.c | 110 +++++++++++++++++++++++------- drivers/media/usb/uvc/uvcvideo.h | 28 ++++++++- 3 files changed, 116 insertions(+), 24 deletions(-) diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c index bc369a0934a3..e61a6d26e812 100644 --- a/drivers/media/usb/uvc/uvc_driver.c +++ b/drivers/media/usb/uvc/uvc_driver.c @@ -1883,6 +1883,8 @@ static void uvc_unregister_video(struct uvc_device *dev) video_unregister_device(&stream->vdev); video_unregister_device(&stream->meta.vdev); + destroy_workqueue(stream->async_wq); + uvc_debugfs_cleanup_stream(stream); } } diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c index 7a7779e1b466..ce9e40444507 100644 --- a/drivers/media/usb/uvc/uvc_video.c +++ b/drivers/media/usb/uvc/uvc_video.c @@ -1094,21 +1094,54 @@ static int uvc_video_decode_start(struct uvc_streaming *stream, return data[0]; } -static void uvc_video_decode_data(struct uvc_streaming *stream, +/* + * uvc_video_decode_data_work: Asynchronous memcpy processing + * + * Copy URB data to video buffers in process context, releasing buffer + * references and requeuing the URB when done. + */ +static void uvc_video_copy_data_work(struct work_struct *work) +{ + struct uvc_urb *uvc_urb = container_of(work, struct uvc_urb, work); + unsigned int i; + int ret; + + for (i = 0; i < uvc_urb->async_operations; i++) { + struct uvc_copy_op *op = &uvc_urb->copy_operations[i]; + + memcpy(op->dst, op->src, op->len); + + /* Release reference taken on this buffer. */ + uvc_queue_buffer_release(op->buf); + } + + ret = usb_submit_urb(uvc_urb->urb, GFP_KERNEL); + if (ret < 0) + uvc_printk(KERN_ERR, "Failed to resubmit video URB (%d).\n", + ret); +} + +static void uvc_video_decode_data(struct uvc_urb *uvc_urb, struct uvc_buffer *buf, const u8 *data, int len) { - unsigned int maxlen, nbytes; - void *mem; + unsigned int active_op = uvc_urb->async_operations; + struct uvc_copy_op *op = &uvc_urb->copy_operations[active_op]; + unsigned int maxlen; if (len <= 0) return; - /* Copy the video data to the buffer. */ maxlen = buf->length - buf->bytesused; - mem = buf->mem + buf->bytesused; - nbytes = min((unsigned int)len, maxlen); - memcpy(mem, data, nbytes); - buf->bytesused += nbytes; + + /* Take a buffer reference for async work. */ + kref_get(&buf->ref); + + op->buf = buf; + op->src = data; + op->dst = buf->mem + buf->bytesused; + op->len = min_t(unsigned int, len, maxlen); + + buf->bytesused += op->len; /* Complete the current frame if the buffer size was exceeded. */ if (len > maxlen) { @@ -1116,6 +1149,8 @@ static void uvc_video_decode_data(struct uvc_streaming *stream, buf->error = 1; buf->state = UVC_BUF_STATE_READY; } + + uvc_urb->async_operations++; } static void uvc_video_decode_end(struct uvc_streaming *stream, @@ -1324,7 +1359,7 @@ static void uvc_video_decode_isoc(struct uvc_urb *uvc_urb, uvc_video_decode_meta(stream, meta_buf, mem, ret); /* Decode the payload data. */ - uvc_video_decode_data(stream, buf, mem + ret, + uvc_video_decode_data(uvc_urb, buf, mem + ret, urb->iso_frame_desc[i].actual_length - ret); /* Process the header again. */ @@ -1384,9 +1419,9 @@ static void uvc_video_decode_bulk(struct uvc_urb *uvc_urb, * sure buf is never dereferenced if NULL. */ - /* Process video data. */ + /* Prepare video data for processing. */ if (!stream->bulk.skip_payload && buf != NULL) - uvc_video_decode_data(stream, buf, mem, len); + uvc_video_decode_data(uvc_urb, buf, mem, len); /* Detect the payload end by a URB smaller than the maximum size (or * a payload size equal to the maximum) and process the header again. @@ -1472,7 +1507,7 @@ static void uvc_video_complete(struct urb *urb) uvc_printk(KERN_WARNING, "Non-zero status (%d) in video " "completion handler.\n", urb->status); /* fall through */ - case -ENOENT: /* usb_kill_urb() called. */ + case -ENOENT: /* usb_poison_urb() called. */ if (stream->frozen) return; /* fall through */ @@ -1494,12 +1529,26 @@ static void uvc_video_complete(struct urb *urb) spin_unlock_irqrestore(&qmeta->irqlock, flags); } + /* Re-initialise the URB async work. */ + uvc_urb->async_operations = 0; + + /* + * Process the URB headers, and optionally queue expensive memcpy tasks + * to be deferred to a work queue. + */ stream->decode(uvc_urb, buf, buf_meta); - if ((ret = usb_submit_urb(urb, GFP_ATOMIC)) < 0) { - uvc_printk(KERN_ERR, "Failed to resubmit video URB (%d).\n", - ret); + /* If no async work is needed, resubmit the URB immediately. */ + if (!uvc_urb->async_operations) { + ret = usb_submit_urb(uvc_urb->urb, GFP_ATOMIC); + if (ret < 0) + uvc_printk(KERN_ERR, + "Failed to resubmit video URB (%d).\n", + ret); + return; } + + queue_work(stream->async_wq, &uvc_urb->work); } /* @@ -1594,20 +1643,22 @@ static int uvc_alloc_urb_buffers(struct uvc_streaming *stream, */ static void uvc_uninit_video(struct uvc_streaming *stream, int free_buffers) { - struct urb *urb; - unsigned int i; + struct uvc_urb *uvc_urb; uvc_video_stats_stop(stream); - for (i = 0; i < UVC_URBS; ++i) { - struct uvc_urb *uvc_urb = &stream->uvc_urb[i]; + /* + * We must poison the URBs rather than kill them to ensure that even + * after the completion handler returns, any asynchronous workqueues + * will be prevented from resubmitting the URBs. + */ + for_each_uvc_urb(uvc_urb, stream) + usb_poison_urb(uvc_urb->urb); - urb = uvc_urb->urb; - if (urb == NULL) - continue; + flush_workqueue(stream->async_wq); - usb_kill_urb(urb); - usb_free_urb(urb); + for_each_uvc_urb(uvc_urb, stream) { + usb_free_urb(uvc_urb->urb); uvc_urb->urb = NULL; } @@ -1932,6 +1983,7 @@ int uvc_video_init(struct uvc_streaming *stream) struct uvc_streaming_control *probe = &stream->ctrl; struct uvc_format *format = NULL; struct uvc_frame *frame = NULL; + struct uvc_urb *uvc_urb; unsigned int i; int ret; @@ -2017,6 +2069,16 @@ int uvc_video_init(struct uvc_streaming *stream) } } + /* Allocate a stream specific work queue for asynchronous tasks. */ + stream->async_wq = alloc_workqueue("uvcvideo", WQ_UNBOUND | WQ_HIGHPRI, + 0); + if (!stream->async_wq) + return -ENOMEM; + + /* Prepare asynchronous work items. */ + for_each_uvc_urb(uvc_urb, stream) + INIT_WORK(&uvc_urb->work, uvc_video_copy_data_work); + return 0; } diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h index 1bc17da7f3d4..0953e2e59a79 100644 --- a/drivers/media/usb/uvc/uvcvideo.h +++ b/drivers/media/usb/uvc/uvcvideo.h @@ -491,12 +491,30 @@ struct uvc_stats_stream { #define UVC_METATADA_BUF_SIZE 1024 /** + * struct uvc_copy_op: Context structure to schedule asynchronous memcpy + * + * @buf: active buf object for this operation + * @dst: copy destination address + * @src: copy source address + * @len: copy length + */ +struct uvc_copy_op { + struct uvc_buffer *buf; + void *dst; + const __u8 *src; + size_t len; +}; + +/** * struct uvc_urb - URB context management structure * * @urb: the URB described by this context structure * @stream: UVC streaming context * @buffer: memory storage for the URB * @dma: DMA coherent addressing for the urb_buffer + * @async_operations: counter to indicate the number of copy operations + * @copy_operations: work descriptors for asynchronous copy operations + * @work: work queue entry for asynchronous decode */ struct uvc_urb { struct urb *urb; @@ -504,6 +522,10 @@ struct uvc_urb { char *buffer; dma_addr_t dma; + + unsigned int async_operations; + struct uvc_copy_op copy_operations[UVC_MAX_PACKETS]; + struct work_struct work; }; struct uvc_streaming { @@ -536,6 +558,7 @@ struct uvc_streaming { /* Buffers queue. */ unsigned int frozen : 1; struct uvc_video_queue queue; + struct workqueue_struct *async_wq; void (*decode)(struct uvc_urb *uvc_urb, struct uvc_buffer *buf, struct uvc_buffer *meta_buf); @@ -589,6 +612,11 @@ struct uvc_streaming { } clock; }; +#define for_each_uvc_urb(uvc_urb, uvc_streaming) \ + for ((uvc_urb) = &(uvc_streaming)->uvc_urb[0]; \ + (uvc_urb) < &(uvc_streaming)->uvc_urb[UVC_URBS]; \ + ++(uvc_urb)) + struct uvc_device_info { u32 quirks; u32 meta_format; From patchwork Tue Nov 6 21:27:18 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kieran Bingham X-Patchwork-Id: 10671427 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 8D00614E2 for ; Tue, 6 Nov 2018 21:27:36 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 7D8042AF66 for ; Tue, 6 Nov 2018 21:27:36 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 719672AF69; Tue, 6 Nov 2018 21:27:36 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 047382AF6E for ; Tue, 6 Nov 2018 21:27:36 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727130AbeKGGyr (ORCPT ); Wed, 7 Nov 2018 01:54:47 -0500 Received: from perceval.ideasonboard.com ([213.167.242.64]:55690 "EHLO perceval.ideasonboard.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726282AbeKGGyr (ORCPT ); Wed, 7 Nov 2018 01:54:47 -0500 Received: from localhost.localdomain (cpc89242-aztw30-2-0-cust488.18-1.cable.virginm.net [86.31.129.233]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 5EA81593; Tue, 6 Nov 2018 22:27:29 +0100 (CET) From: Kieran Bingham To: Laurent Pinchart , linux-media@vger.kernel.org Cc: Guennadi Liakhovetski , Olivier BRAUN , Troy Kisky , Randy Dunlap , Philipp Zabel , Ezequiel Garcia , Kieran Bingham Subject: [PATCH v5 7/9] media: uvcvideo: Split uvc_video_enable into two Date: Tue, 6 Nov 2018 21:27:18 +0000 Message-Id: <5a6b4702bd9da438a0635901d2e44ca737842655.1541534872.git-series.kieran.bingham@ideasonboard.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: References: In-Reply-To: References: Sender: linux-media-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Kieran Bingham uvc_video_enable() is used both to start and stop the video stream object, however the single function entry point shares no code between the two operations. Split the function into two distinct calls, and rename to uvc_video_start_streaming() and uvc_video_stop_streaming() as appropriate. Signed-off-by: Kieran Bingham Reviewed-by: Laurent Pinchart --- drivers/media/usb/uvc/uvc_queue.c | 4 +- drivers/media/usb/uvc/uvc_video.c | 56 +++++++++++++++----------------- drivers/media/usb/uvc/uvcvideo.h | 3 +- 3 files changed, 31 insertions(+), 32 deletions(-) diff --git a/drivers/media/usb/uvc/uvc_queue.c b/drivers/media/usb/uvc/uvc_queue.c index cd8c03341de0..682698ec1118 100644 --- a/drivers/media/usb/uvc/uvc_queue.c +++ b/drivers/media/usb/uvc/uvc_queue.c @@ -176,7 +176,7 @@ static int uvc_start_streaming(struct vb2_queue *vq, unsigned int count) queue->buf_used = 0; - ret = uvc_video_enable(stream, 1); + ret = uvc_video_start_streaming(stream); if (ret == 0) return 0; @@ -194,7 +194,7 @@ static void uvc_stop_streaming(struct vb2_queue *vq) lockdep_assert_irqs_enabled(); if (vq->type != V4L2_BUF_TYPE_META_CAPTURE) - uvc_video_enable(uvc_queue_to_stream(queue), 0); + uvc_video_stop_streaming(uvc_queue_to_stream(queue)); spin_lock_irq(&queue->irqlock); uvc_queue_return_buffers(queue, UVC_BUF_STATE_ERROR); diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c index ce9e40444507..0d35e933856a 100644 --- a/drivers/media/usb/uvc/uvc_video.c +++ b/drivers/media/usb/uvc/uvc_video.c @@ -2082,38 +2082,10 @@ int uvc_video_init(struct uvc_streaming *stream) return 0; } -/* - * Enable or disable the video stream. - */ -int uvc_video_enable(struct uvc_streaming *stream, int enable) +int uvc_video_start_streaming(struct uvc_streaming *stream) { int ret; - if (!enable) { - uvc_uninit_video(stream, 1); - if (stream->intf->num_altsetting > 1) { - usb_set_interface(stream->dev->udev, - stream->intfnum, 0); - } else { - /* UVC doesn't specify how to inform a bulk-based device - * when the video stream is stopped. Windows sends a - * CLEAR_FEATURE(HALT) request to the video streaming - * bulk endpoint, mimic the same behaviour. - */ - unsigned int epnum = stream->header.bEndpointAddress - & USB_ENDPOINT_NUMBER_MASK; - unsigned int dir = stream->header.bEndpointAddress - & USB_ENDPOINT_DIR_MASK; - unsigned int pipe; - - pipe = usb_sndbulkpipe(stream->dev->udev, epnum) | dir; - usb_clear_halt(stream->dev->udev, pipe); - } - - uvc_video_clock_cleanup(stream); - return 0; - } - ret = uvc_video_clock_init(stream); if (ret < 0) return ret; @@ -2136,3 +2108,29 @@ int uvc_video_enable(struct uvc_streaming *stream, int enable) return ret; } + +int uvc_video_stop_streaming(struct uvc_streaming *stream) +{ + uvc_uninit_video(stream, 1); + if (stream->intf->num_altsetting > 1) { + usb_set_interface(stream->dev->udev, + stream->intfnum, 0); + } else { + /* UVC doesn't specify how to inform a bulk-based device + * when the video stream is stopped. Windows sends a + * CLEAR_FEATURE(HALT) request to the video streaming + * bulk endpoint, mimic the same behaviour. + */ + unsigned int epnum = stream->header.bEndpointAddress + & USB_ENDPOINT_NUMBER_MASK; + unsigned int dir = stream->header.bEndpointAddress + & USB_ENDPOINT_DIR_MASK; + unsigned int pipe; + + pipe = usb_sndbulkpipe(stream->dev->udev, epnum) | dir; + usb_clear_halt(stream->dev->udev, pipe); + } + + uvc_video_clock_cleanup(stream); + return 0; +} diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h index 0953e2e59a79..c0a120496a1f 100644 --- a/drivers/media/usb/uvc/uvcvideo.h +++ b/drivers/media/usb/uvc/uvcvideo.h @@ -784,7 +784,8 @@ void uvc_mc_cleanup_entity(struct uvc_entity *entity); int uvc_video_init(struct uvc_streaming *stream); int uvc_video_suspend(struct uvc_streaming *stream); int uvc_video_resume(struct uvc_streaming *stream, int reset); -int uvc_video_enable(struct uvc_streaming *stream, int enable); +int uvc_video_start_streaming(struct uvc_streaming *stream); +int uvc_video_stop_streaming(struct uvc_streaming *stream); int uvc_probe_video(struct uvc_streaming *stream, struct uvc_streaming_control *probe); int uvc_query_ctrl(struct uvc_device *dev, u8 query, u8 unit, From patchwork Tue Nov 6 21:27:19 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kieran Bingham X-Patchwork-Id: 10671429 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 7AAEF14E2 for ; Tue, 6 Nov 2018 21:27:37 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 6C6822AF66 for ; Tue, 6 Nov 2018 21:27:37 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 609082AF6E; Tue, 6 Nov 2018 21:27:37 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id F02F12AF66 for ; Tue, 6 Nov 2018 21:27:36 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727212AbeKGGys (ORCPT ); Wed, 7 Nov 2018 01:54:48 -0500 Received: from perceval.ideasonboard.com ([213.167.242.64]:55676 "EHLO perceval.ideasonboard.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726726AbeKGGys (ORCPT ); Wed, 7 Nov 2018 01:54:48 -0500 Received: from localhost.localdomain (cpc89242-aztw30-2-0-cust488.18-1.cable.virginm.net [86.31.129.233]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id E2EE9594; Tue, 6 Nov 2018 22:27:29 +0100 (CET) From: Kieran Bingham To: Laurent Pinchart , linux-media@vger.kernel.org Cc: Guennadi Liakhovetski , Olivier BRAUN , Troy Kisky , Randy Dunlap , Philipp Zabel , Ezequiel Garcia , Kieran Bingham Subject: [PATCH v5 8/9] media: uvcvideo: Rename uvc_{un,}init_video() Date: Tue, 6 Nov 2018 21:27:19 +0000 Message-Id: <0b2eb102e4d0c4f746469b6aa0528ace9345ddde.1541534872.git-series.kieran.bingham@ideasonboard.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: References: In-Reply-To: References: Sender: linux-media-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Kieran Bingham We have both uvc_init_video() and uvc_video_init() calls which can be quite confusing to determine the process for each. Now that video uvc_video_enable() has been renamed to uvc_video_start_streaming(), adapt these calls to suit the new flow. Rename uvc_init_video() to uvc_video_start() and uvc_uninit_video() to uvc_video_stop(). Signed-off-by: Kieran Bingham --- drivers/media/usb/uvc/uvc_video.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c index 0d35e933856a..020022e6ade4 100644 --- a/drivers/media/usb/uvc/uvc_video.c +++ b/drivers/media/usb/uvc/uvc_video.c @@ -1641,7 +1641,7 @@ static int uvc_alloc_urb_buffers(struct uvc_streaming *stream, /* * Uninitialize isochronous/bulk URBs and free transfer buffers. */ -static void uvc_uninit_video(struct uvc_streaming *stream, int free_buffers) +static void uvc_video_stop(struct uvc_streaming *stream, int free_buffers) { struct uvc_urb *uvc_urb; @@ -1718,7 +1718,7 @@ static int uvc_init_video_isoc(struct uvc_streaming *stream, urb = usb_alloc_urb(npackets, gfp_flags); if (urb == NULL) { - uvc_uninit_video(stream, 1); + uvc_video_stop(stream, 1); return -ENOMEM; } @@ -1786,7 +1786,7 @@ static int uvc_init_video_bulk(struct uvc_streaming *stream, urb = usb_alloc_urb(0, gfp_flags); if (urb == NULL) { - uvc_uninit_video(stream, 1); + uvc_video_stop(stream, 1); return -ENOMEM; } @@ -1806,7 +1806,7 @@ static int uvc_init_video_bulk(struct uvc_streaming *stream, /* * Initialize isochronous/bulk URBs and allocate transfer buffers. */ -static int uvc_init_video(struct uvc_streaming *stream, gfp_t gfp_flags) +static int uvc_video_start(struct uvc_streaming *stream, gfp_t gfp_flags) { struct usb_interface *intf = stream->intf; struct usb_host_endpoint *ep; @@ -1894,7 +1894,7 @@ static int uvc_init_video(struct uvc_streaming *stream, gfp_t gfp_flags) if (ret < 0) { uvc_printk(KERN_ERR, "Failed to submit URB %u " "(%d).\n", i, ret); - uvc_uninit_video(stream, 1); + uvc_video_stop(stream, 1); return ret; } } @@ -1925,7 +1925,7 @@ int uvc_video_suspend(struct uvc_streaming *stream) return 0; stream->frozen = 1; - uvc_uninit_video(stream, 0); + uvc_video_stop(stream, 0); usb_set_interface(stream->dev->udev, stream->intfnum, 0); return 0; } @@ -1961,7 +1961,7 @@ int uvc_video_resume(struct uvc_streaming *stream, int reset) if (ret < 0) return ret; - return uvc_init_video(stream, GFP_NOIO); + return uvc_video_start(stream, GFP_NOIO); } /* ------------------------------------------------------------------------ @@ -2095,7 +2095,7 @@ int uvc_video_start_streaming(struct uvc_streaming *stream) if (ret < 0) goto error_commit; - ret = uvc_init_video(stream, GFP_KERNEL); + ret = uvc_video_start(stream, GFP_KERNEL); if (ret < 0) goto error_video; @@ -2111,7 +2111,7 @@ int uvc_video_start_streaming(struct uvc_streaming *stream) int uvc_video_stop_streaming(struct uvc_streaming *stream) { - uvc_uninit_video(stream, 1); + uvc_video_stop(stream, 1); if (stream->intf->num_altsetting > 1) { usb_set_interface(stream->dev->udev, stream->intfnum, 0); From patchwork Tue Nov 6 21:27:20 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kieran Bingham X-Patchwork-Id: 10671431 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 4C2221709 for ; Tue, 6 Nov 2018 21:27:38 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 3D0D02AF66 for ; Tue, 6 Nov 2018 21:27:38 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 319F72AF6E; Tue, 6 Nov 2018 21:27:38 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id A96222AF66 for ; Tue, 6 Nov 2018 21:27:37 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727222AbeKGGyt (ORCPT ); Wed, 7 Nov 2018 01:54:49 -0500 Received: from perceval.ideasonboard.com ([213.167.242.64]:55690 "EHLO perceval.ideasonboard.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726282AbeKGGyt (ORCPT ); Wed, 7 Nov 2018 01:54:49 -0500 Received: from localhost.localdomain (cpc89242-aztw30-2-0-cust488.18-1.cable.virginm.net [86.31.129.233]) by perceval.ideasonboard.com (Postfix) with ESMTPSA id 74285595; Tue, 6 Nov 2018 22:27:30 +0100 (CET) From: Kieran Bingham To: Laurent Pinchart , linux-media@vger.kernel.org Cc: Guennadi Liakhovetski , Olivier BRAUN , Troy Kisky , Randy Dunlap , Philipp Zabel , Ezequiel Garcia , Kieran Bingham Subject: [PATCH v5 9/9] media: uvcvideo: Utilise for_each_uvc_urb iterator Date: Tue, 6 Nov 2018 21:27:20 +0000 Message-Id: <8e669260c648ec44eefce9f554c5a871311832d9.1541534872.git-series.kieran.bingham@ideasonboard.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: References: In-Reply-To: References: Sender: linux-media-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Kieran Bingham A new iterator is available for processing UVC URB structures. This simplifies the processing of the internal stream data. Convert the manual loop iterators to the new helper, adding an index helper to keep the existing debug print. Signed-off-by: Kieran Bingham --- This patch converts to using the iterator which for most hunks makes sense. The only one with uncertainty is in uvc_alloc_urb_buffers() where the loop index is used to determine if all the buffers were successfully allocated. As the loop index is not incremented by the loops, we can obtain the buffer index - but then we are offset and out-by-one. Adjusting this in the code is fine - but at that point it feels like it's not adding much value. I've left that hunk in for this patch - but that part could be reverted if desired - unless anyone has a better rework of the buffer check? drivers/media/usb/uvc/uvc_video.c | 51 ++++++++++++++++---------------- drivers/media/usb/uvc/uvcvideo.h | 3 ++- 2 files changed, 29 insertions(+), 25 deletions(-) diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c index 020022e6ade4..f6e5db7ea50e 100644 --- a/drivers/media/usb/uvc/uvc_video.c +++ b/drivers/media/usb/uvc/uvc_video.c @@ -1556,20 +1556,19 @@ static void uvc_video_complete(struct urb *urb) */ static void uvc_free_urb_buffers(struct uvc_streaming *stream) { - unsigned int i; + struct uvc_urb *uvc_urb; - for (i = 0; i < UVC_URBS; ++i) { - struct uvc_urb *uvc_urb = &stream->uvc_urb[i]; + for_each_uvc_urb(uvc_urb, stream) { + if (!uvc_urb->buffer) + continue; - if (uvc_urb->buffer) { #ifndef CONFIG_DMA_NONCOHERENT - usb_free_coherent(stream->dev->udev, stream->urb_size, - uvc_urb->buffer, uvc_urb->dma); + usb_free_coherent(stream->dev->udev, stream->urb_size, + uvc_urb->buffer, uvc_urb->dma); #else - kfree(uvc_urb->buffer); + kfree(uvc_urb->buffer); #endif - uvc_urb->buffer = NULL; - } + uvc_urb->buffer = NULL; } stream->urb_size = 0; @@ -1589,8 +1588,9 @@ static void uvc_free_urb_buffers(struct uvc_streaming *stream) static int uvc_alloc_urb_buffers(struct uvc_streaming *stream, unsigned int size, unsigned int psize, gfp_t gfp_flags) { + struct uvc_urb *uvc_urb; unsigned int npackets; - unsigned int i; + unsigned int i = 0; /* Buffers are already allocated, bail out. */ if (stream->urb_size) @@ -1605,8 +1605,12 @@ static int uvc_alloc_urb_buffers(struct uvc_streaming *stream, /* Retry allocations until one succeed. */ for (; npackets > 1; npackets /= 2) { - for (i = 0; i < UVC_URBS; ++i) { - struct uvc_urb *uvc_urb = &stream->uvc_urb[i]; + for_each_uvc_urb(uvc_urb, stream) { + /* + * Track how many URBs we allocate, adding one to the + * index to account for our zero index. + */ + i = uvc_urb_index(uvc_urb) + 1; stream->urb_size = psize * npackets; #ifndef CONFIG_DMA_NONCOHERENT @@ -1700,7 +1704,8 @@ static int uvc_init_video_isoc(struct uvc_streaming *stream, struct usb_host_endpoint *ep, gfp_t gfp_flags) { struct urb *urb; - unsigned int npackets, i, j; + struct uvc_urb *uvc_urb; + unsigned int npackets, j; u16 psize; u32 size; @@ -1713,9 +1718,7 @@ static int uvc_init_video_isoc(struct uvc_streaming *stream, size = npackets * psize; - for (i = 0; i < UVC_URBS; ++i) { - struct uvc_urb *uvc_urb = &stream->uvc_urb[i]; - + for_each_uvc_urb(uvc_urb, stream) { urb = usb_alloc_urb(npackets, gfp_flags); if (urb == NULL) { uvc_video_stop(stream, 1); @@ -1757,7 +1760,8 @@ static int uvc_init_video_bulk(struct uvc_streaming *stream, struct usb_host_endpoint *ep, gfp_t gfp_flags) { struct urb *urb; - unsigned int npackets, pipe, i; + struct uvc_urb *uvc_urb; + unsigned int npackets, pipe; u16 psize; u32 size; @@ -1781,9 +1785,7 @@ static int uvc_init_video_bulk(struct uvc_streaming *stream, if (stream->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) size = 0; - for (i = 0; i < UVC_URBS; ++i) { - struct uvc_urb *uvc_urb = &stream->uvc_urb[i]; - + for_each_uvc_urb(uvc_urb, stream) { urb = usb_alloc_urb(0, gfp_flags); if (urb == NULL) { uvc_video_stop(stream, 1); @@ -1810,6 +1812,7 @@ static int uvc_video_start(struct uvc_streaming *stream, gfp_t gfp_flags) { struct usb_interface *intf = stream->intf; struct usb_host_endpoint *ep; + struct uvc_urb *uvc_urb; unsigned int i; int ret; @@ -1887,13 +1890,11 @@ static int uvc_video_start(struct uvc_streaming *stream, gfp_t gfp_flags) return ret; /* Submit the URBs. */ - for (i = 0; i < UVC_URBS; ++i) { - struct uvc_urb *uvc_urb = &stream->uvc_urb[i]; - + for_each_uvc_urb(uvc_urb, stream) { ret = usb_submit_urb(uvc_urb->urb, gfp_flags); if (ret < 0) { - uvc_printk(KERN_ERR, "Failed to submit URB %u " - "(%d).\n", i, ret); + uvc_printk(KERN_ERR, "Failed to submit URB %u (%d).\n", + uvc_urb_index(uvc_urb), ret); uvc_video_stop(stream, 1); return ret; } diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h index c0a120496a1f..6a0f1b59356c 100644 --- a/drivers/media/usb/uvc/uvcvideo.h +++ b/drivers/media/usb/uvc/uvcvideo.h @@ -617,6 +617,9 @@ struct uvc_streaming { (uvc_urb) < &(uvc_streaming)->uvc_urb[UVC_URBS]; \ ++(uvc_urb)) +#define uvc_urb_index(uvc_urb) \ + (unsigned int)((uvc_urb) - (&(uvc_urb)->stream->uvc_urb[0])) + struct uvc_device_info { u32 quirks; u32 meta_format;