usb: gadget: uvc: make uvc_num_requests depend on gadget speed
authorMichael Grzeschik <m.grzeschik@pengutronix.de>
Mon, 28 Jun 2021 15:53:08 +0000 (17:53 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 27 Jul 2021 13:59:18 +0000 (15:59 +0200)
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>
drivers/usb/gadget/function/uvc.h
drivers/usb/gadget/function/uvc_queue.c
drivers/usb/gadget/function/uvc_video.c

index 23ee253..52f8941 100644 (file)
@@ -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;
@@ -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;
 
index 61e2c94..ff0cc08 100644 (file)
@@ -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;
@@ -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;
 }
 
index 633e23d..303cb42 100644 (file)
@@ -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;
 
@@ -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);
@@ -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;
@@ -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);