Skip to content

Commit

Permalink
usb: gadget: uvc: rework pump worker to avoid while loop
Browse files Browse the repository at this point in the history
The uvc_video_enable function is calling cancel_work_sync which will be
blocking as long as new requests will be queued with the while loop. To
ensure an earlier stop in the pumping loop in this particular case we
rework the worker to requeue itself on every requests. Since the worker
is already running prioritized, the scheduling overhad did not have real
impact on the performance.

Signed-off-by: Michael Grzeschik <m.grzeschik@pengutronix.de>
Link: https://lore.kernel.org/r/20230911140530.2995138-4-m.grzeschik@pengutronix.de
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
Michael Grzeschik authored and Greg Kroah-Hartman committed Oct 2, 2023
1 parent 52a39f2 commit bb00788
Showing 1 changed file with 14 additions and 6 deletions.
20 changes: 14 additions & 6 deletions drivers/usb/gadget/function/uvc_video.c
Original file line number Diff line number Diff line change
Expand Up @@ -397,7 +397,7 @@ static void uvcg_video_pump(struct work_struct *work)
bool buf_done;
int ret;

while (video->ep->enabled && uvc->state == UVC_STATE_STREAMING) {
if (video->ep->enabled && uvc->state == UVC_STATE_STREAMING) {
/*
* Retrieve the first available USB request, protected by the
* request lock.
Expand All @@ -409,6 +409,11 @@ static void uvcg_video_pump(struct work_struct *work)
}
req = list_first_entry(&video->req_free, struct usb_request,
list);
if (!req) {
spin_unlock_irqrestore(&video->req_lock, flags);
return;
}

list_del(&req->list);
spin_unlock_irqrestore(&video->req_lock, flags);

Expand Down Expand Up @@ -437,7 +442,7 @@ static void uvcg_video_pump(struct work_struct *work)
* further.
*/
spin_unlock_irqrestore(&queue->irqlock, flags);
break;
goto out;
}

/*
Expand Down Expand Up @@ -470,20 +475,23 @@ static void uvcg_video_pump(struct work_struct *work)
/* Queue the USB request */
ret = uvcg_video_ep_queue(video, req);
spin_unlock_irqrestore(&queue->irqlock, flags);

if (ret < 0) {
uvcg_queue_cancel(queue, 0);
break;
goto out;
}

/* Endpoint now owns the request */
req = NULL;
video->req_int_count++;
} else {
return;
}

if (!req)
return;
if (uvc->state == UVC_STATE_STREAMING)
queue_work(video->async_wq, &video->pump);

return;
out:
spin_lock_irqsave(&video->req_lock, flags);
list_add_tail(&req->list, &video->req_free);
spin_unlock_irqrestore(&video->req_lock, flags);
Expand Down

0 comments on commit bb00788

Please sign in to comment.