Skip to content

Commit dc97c95

Browse files
mgrzeschikgregkh
authored andcommitted
usb: gadget: uvc: only enqueue zero length requests in potential underrun
The complete handler will at least be called after 16 requests have completed, but will still handle all finisher requests. Since we have to maintain a costant filling in the isoc queue we ensure this by adding zero length requests. By counting the amount enqueued requests we can ensure that the queue is never underrun and only need to get active if the queue is running critical. This patch is setting 32 as the critical level, which is twice the request amount that is needed to create interrupts. To properly solve the amount of zero length requests that needs to be held in the hardware after one interrupt needs to be measured and depends on the runtime of the first enqueue run after the interrupt triggered. For now we just use twice the amount of requests between an interrupt. Signed-off-by: Michael Grzeschik <[email protected]> Link: https://lore.kernel.org/r/20240403-uvc_request_length_by_interval-v7-2-e224bb1035f0@pengutronix.de Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent adc292d commit dc97c95

File tree

2 files changed

+21
-1
lines changed

2 files changed

+21
-1
lines changed

drivers/usb/gadget/function/uvc.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,9 @@ extern unsigned int uvc_gadget_trace_param;
7171

7272
#define UVCG_REQUEST_HEADER_LEN 12
7373

74+
#define UVCG_REQ_MAX_INT_COUNT 16
75+
#define UVCG_REQ_MAX_ZERO_COUNT (2 * UVCG_REQ_MAX_INT_COUNT)
76+
7477
/* ------------------------------------------------------------------------
7578
* Structures
7679
*/
@@ -91,6 +94,8 @@ struct uvc_video {
9194
struct work_struct pump;
9295
struct workqueue_struct *async_wq;
9396

97+
atomic_t queued;
98+
9499
/* Frame parameters */
95100
u8 bpp;
96101
u32 fcc;

drivers/usb/gadget/function/uvc_video.c

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,8 @@ static int uvcg_video_ep_queue(struct uvc_video *video, struct usb_request *req)
269269
}
270270
}
271271

272+
atomic_inc(&video->queued);
273+
272274
return ret;
273275
}
274276

@@ -304,7 +306,7 @@ static int uvcg_video_usb_req_queue(struct uvc_video *video,
304306
*/
305307
if (list_empty(&video->req_free) || ureq->last_buf ||
306308
!(video->req_int_count %
307-
DIV_ROUND_UP(video->uvc_num_requests, 4))) {
309+
min(DIV_ROUND_UP(video->uvc_num_requests, 4), UVCG_REQ_MAX_INT_COUNT))) {
308310
video->req_int_count = 0;
309311
req->no_interrupt = 0;
310312
} else {
@@ -379,6 +381,7 @@ uvc_video_complete(struct usb_ep *ep, struct usb_request *req)
379381
int ret = 0;
380382

381383
spin_lock_irqsave(&video->req_lock, flags);
384+
atomic_dec(&video->queued);
382385
if (!video->is_enabled) {
383386
/*
384387
* When is_enabled is false, uvcg_video_disable() ensures
@@ -466,6 +469,16 @@ uvc_video_complete(struct usb_ep *ep, struct usb_request *req)
466469
* happen.
467470
*/
468471
queue_work(video->async_wq, &video->pump);
472+
} else if (atomic_read(&video->queued) > UVCG_REQ_MAX_ZERO_COUNT) {
473+
list_add_tail(&to_queue->list, &video->req_free);
474+
/*
475+
* There is a new free request - wake up the pump.
476+
*/
477+
queue_work(video->async_wq, &video->pump);
478+
479+
spin_unlock_irqrestore(&video->req_lock, flags);
480+
481+
return;
469482
}
470483
/*
471484
* Queue to the endpoint. The actual queueing to ep will
@@ -756,6 +769,8 @@ int uvcg_video_enable(struct uvc_video *video)
756769

757770
video->req_int_count = 0;
758771

772+
atomic_set(&video->queued, 0);
773+
759774
uvc_video_ep_queue_initial_requests(video);
760775
queue_work(video->async_wq, &video->pump);
761776

0 commit comments

Comments
 (0)