Skip to content

Commit

Permalink
usb: gadget: uvc: only enqueue zero length requests in potential unde…
Browse files Browse the repository at this point in the history
…rrun

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 <m.grzeschik@pengutronix.de>
Link: https://lore.kernel.org/r/20240403-uvc_request_length_by_interval-v7-2-e224bb1035f0@pengutronix.de
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
Michael Grzeschik authored and Greg Kroah-Hartman committed Oct 17, 2024
1 parent adc292d commit dc97c95
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 1 deletion.
5 changes: 5 additions & 0 deletions drivers/usb/gadget/function/uvc.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@ extern unsigned int uvc_gadget_trace_param;

#define UVCG_REQUEST_HEADER_LEN 12

#define UVCG_REQ_MAX_INT_COUNT 16
#define UVCG_REQ_MAX_ZERO_COUNT (2 * UVCG_REQ_MAX_INT_COUNT)

/* ------------------------------------------------------------------------
* Structures
*/
Expand All @@ -91,6 +94,8 @@ struct uvc_video {
struct work_struct pump;
struct workqueue_struct *async_wq;

atomic_t queued;

/* Frame parameters */
u8 bpp;
u32 fcc;
Expand Down
17 changes: 16 additions & 1 deletion drivers/usb/gadget/function/uvc_video.c
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,8 @@ static int uvcg_video_ep_queue(struct uvc_video *video, struct usb_request *req)
}
}

atomic_inc(&video->queued);

return ret;
}

Expand Down Expand Up @@ -304,7 +306,7 @@ static int uvcg_video_usb_req_queue(struct uvc_video *video,
*/
if (list_empty(&video->req_free) || ureq->last_buf ||
!(video->req_int_count %
DIV_ROUND_UP(video->uvc_num_requests, 4))) {
min(DIV_ROUND_UP(video->uvc_num_requests, 4), UVCG_REQ_MAX_INT_COUNT))) {
video->req_int_count = 0;
req->no_interrupt = 0;
} else {
Expand Down Expand Up @@ -379,6 +381,7 @@ uvc_video_complete(struct usb_ep *ep, struct usb_request *req)
int ret = 0;

spin_lock_irqsave(&video->req_lock, flags);
atomic_dec(&video->queued);
if (!video->is_enabled) {
/*
* When is_enabled is false, uvcg_video_disable() ensures
Expand Down Expand Up @@ -466,6 +469,16 @@ uvc_video_complete(struct usb_ep *ep, struct usb_request *req)
* happen.
*/
queue_work(video->async_wq, &video->pump);
} else if (atomic_read(&video->queued) > UVCG_REQ_MAX_ZERO_COUNT) {
list_add_tail(&to_queue->list, &video->req_free);
/*
* There is a new free request - wake up the pump.
*/
queue_work(video->async_wq, &video->pump);

spin_unlock_irqrestore(&video->req_lock, flags);

return;
}
/*
* Queue to the endpoint. The actual queueing to ep will
Expand Down Expand Up @@ -756,6 +769,8 @@ int uvcg_video_enable(struct uvc_video *video)

video->req_int_count = 0;

atomic_set(&video->queued, 0);

uvc_video_ep_queue_initial_requests(video);
queue_work(video->async_wq, &video->pump);

Expand Down

0 comments on commit dc97c95

Please sign in to comment.