Skip to content

Commit

Permalink
usb: gadget: uvc: make uvc_num_requests depend on gadget speed
Browse files Browse the repository at this point in the history
While sending bigger images is possible with USB_SPEED_SUPER it is
better to use more isochronous requests in flight. This patch makes the
number uvc_num_requests dynamic by changing it depending on the gadget
speed.

Reviewed-by: Paul Elder <paul.elder@ideasonboard.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Michael Grzeschik <m.grzeschik@pengutronix.de>
Link: https://lore.kernel.org/r/20210628155311.16762-3-m.grzeschik@pengutronix.de
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
Michael Grzeschik authored and Greg Kroah-Hartman committed Jul 27, 2021
1 parent c6e23b8 commit 9973772
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 25 deletions.
11 changes: 8 additions & 3 deletions drivers/usb/gadget/function/uvc.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,13 +65,17 @@ extern unsigned int uvc_gadget_trace_param;
* Driver specific constants
*/

#define UVC_NUM_REQUESTS 4
#define UVC_MAX_REQUEST_SIZE 64
#define UVC_MAX_EVENTS 4

/* ------------------------------------------------------------------------
* Structures
*/
struct uvc_request {
struct usb_request *req;
u8 *req_buffer;
struct uvc_video *video;
};

struct uvc_video {
struct uvc_device *uvc;
Expand All @@ -87,10 +91,11 @@ struct uvc_video {
unsigned int imagesize;
struct mutex mutex; /* protects frame parameters */

unsigned int uvc_num_requests;

/* Requests */
unsigned int req_size;
struct usb_request *req[UVC_NUM_REQUESTS];
__u8 *req_buffer[UVC_NUM_REQUESTS];
struct uvc_request *ureq;
struct list_head req_free;
spinlock_t req_lock;

Expand Down
6 changes: 6 additions & 0 deletions drivers/usb/gadget/function/uvc_queue.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ static int uvc_queue_setup(struct vb2_queue *vq,
{
struct uvc_video_queue *queue = vb2_get_drv_priv(vq);
struct uvc_video *video = container_of(queue, struct uvc_video, queue);
struct usb_composite_dev *cdev = video->uvc->func.config->cdev;

if (*nbuffers > UVC_MAX_VIDEO_BUFFERS)
*nbuffers = UVC_MAX_VIDEO_BUFFERS;
Expand All @@ -51,6 +52,11 @@ static int uvc_queue_setup(struct vb2_queue *vq,

sizes[0] = video->imagesize;

if (cdev->gadget->speed < USB_SPEED_SUPER)
video->uvc_num_requests = 4;
else
video->uvc_num_requests = 64;

return 0;
}

Expand Down
55 changes: 33 additions & 22 deletions drivers/usb/gadget/function/uvc_video.c
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,8 @@ static int uvcg_video_ep_queue(struct uvc_video *video, struct usb_request *req)
static void
uvc_video_complete(struct usb_ep *ep, struct usb_request *req)
{
struct uvc_video *video = req->context;
struct uvc_request *ureq = req->context;
struct uvc_video *video = ureq->video;
struct uvc_video_queue *queue = &video->queue;
unsigned long flags;

Expand Down Expand Up @@ -177,16 +178,21 @@ uvc_video_free_requests(struct uvc_video *video)
{
unsigned int i;

for (i = 0; i < UVC_NUM_REQUESTS; ++i) {
if (video->req[i]) {
usb_ep_free_request(video->ep, video->req[i]);
video->req[i] = NULL;
if (video->ureq) {
for (i = 0; i < video->uvc_num_requests; ++i) {
if (video->ureq[i].req) {
usb_ep_free_request(video->ep, video->ureq[i].req);
video->ureq[i].req = NULL;
}

if (video->ureq[i].req_buffer) {
kfree(video->ureq[i].req_buffer);
video->ureq[i].req_buffer = NULL;
}
}

if (video->req_buffer[i]) {
kfree(video->req_buffer[i]);
video->req_buffer[i] = NULL;
}
kfree(video->ureq);
video->ureq = NULL;
}

INIT_LIST_HEAD(&video->req_free);
Expand All @@ -207,21 +213,26 @@ uvc_video_alloc_requests(struct uvc_video *video)
* max_t(unsigned int, video->ep->maxburst, 1)
* (video->ep->mult);

for (i = 0; i < UVC_NUM_REQUESTS; ++i) {
video->req_buffer[i] = kmalloc(req_size, GFP_KERNEL);
if (video->req_buffer[i] == NULL)
video->ureq = kcalloc(video->uvc_num_requests, sizeof(struct uvc_request), GFP_KERNEL);
if (video->ureq == NULL)
return -ENOMEM;

for (i = 0; i < video->uvc_num_requests; ++i) {
video->ureq[i].req_buffer = kmalloc(req_size, GFP_KERNEL);
if (video->ureq[i].req_buffer == NULL)
goto error;

video->req[i] = usb_ep_alloc_request(video->ep, GFP_KERNEL);
if (video->req[i] == NULL)
video->ureq[i].req = usb_ep_alloc_request(video->ep, GFP_KERNEL);
if (video->ureq[i].req == NULL)
goto error;

video->req[i]->buf = video->req_buffer[i];
video->req[i]->length = 0;
video->req[i]->complete = uvc_video_complete;
video->req[i]->context = video;
video->ureq[i].req->buf = video->ureq[i].req_buffer;
video->ureq[i].req->length = 0;
video->ureq[i].req->complete = uvc_video_complete;
video->ureq[i].req->context = &video->ureq[i];
video->ureq[i].video = video;

list_add_tail(&video->req[i]->list, &video->req_free);
list_add_tail(&video->ureq[i].req->list, &video->req_free);
}

video->req_size = req_size;
Expand Down Expand Up @@ -312,9 +323,9 @@ int uvcg_video_enable(struct uvc_video *video, int enable)
cancel_work_sync(&video->pump);
uvcg_queue_cancel(&video->queue, 0);

for (i = 0; i < UVC_NUM_REQUESTS; ++i)
if (video->req[i])
usb_ep_dequeue(video->ep, video->req[i]);
for (i = 0; i < video->uvc_num_requests; ++i)
if (video->ureq && video->ureq[i].req)
usb_ep_dequeue(video->ep, video->ureq[i].req);

uvc_video_free_requests(video);
uvcg_queue_enable(&video->queue, 0);
Expand Down

0 comments on commit 9973772

Please sign in to comment.