usb: gadget: uvc: make uvc_num_requests depend on gadget speed

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>
This commit is contained in:
Michael Grzeschik 2021-06-28 17:53:08 +02:00 committed by Greg Kroah-Hartman
parent c6e23b89a9
commit 9973772dbb
3 changed files with 47 additions and 25 deletions

View File

@ -65,13 +65,17 @@ extern unsigned int uvc_gadget_trace_param;
* Driver specific constants * Driver specific constants
*/ */
#define UVC_NUM_REQUESTS 4
#define UVC_MAX_REQUEST_SIZE 64 #define UVC_MAX_REQUEST_SIZE 64
#define UVC_MAX_EVENTS 4 #define UVC_MAX_EVENTS 4
/* ------------------------------------------------------------------------ /* ------------------------------------------------------------------------
* Structures * Structures
*/ */
struct uvc_request {
struct usb_request *req;
u8 *req_buffer;
struct uvc_video *video;
};
struct uvc_video { struct uvc_video {
struct uvc_device *uvc; struct uvc_device *uvc;
@ -87,10 +91,11 @@ struct uvc_video {
unsigned int imagesize; unsigned int imagesize;
struct mutex mutex; /* protects frame parameters */ struct mutex mutex; /* protects frame parameters */
unsigned int uvc_num_requests;
/* Requests */ /* Requests */
unsigned int req_size; unsigned int req_size;
struct usb_request *req[UVC_NUM_REQUESTS]; struct uvc_request *ureq;
__u8 *req_buffer[UVC_NUM_REQUESTS];
struct list_head req_free; struct list_head req_free;
spinlock_t req_lock; spinlock_t req_lock;

View 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_queue *queue = vb2_get_drv_priv(vq);
struct uvc_video *video = container_of(queue, struct uvc_video, queue); 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) if (*nbuffers > UVC_MAX_VIDEO_BUFFERS)
*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; sizes[0] = video->imagesize;
if (cdev->gadget->speed < USB_SPEED_SUPER)
video->uvc_num_requests = 4;
else
video->uvc_num_requests = 64;
return 0; return 0;
} }

View File

@ -145,7 +145,8 @@ static int uvcg_video_ep_queue(struct uvc_video *video, struct usb_request *req)
static void static void
uvc_video_complete(struct usb_ep *ep, struct usb_request *req) 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; struct uvc_video_queue *queue = &video->queue;
unsigned long flags; unsigned long flags;
@ -177,18 +178,23 @@ uvc_video_free_requests(struct uvc_video *video)
{ {
unsigned int i; unsigned int i;
for (i = 0; i < UVC_NUM_REQUESTS; ++i) { if (video->ureq) {
if (video->req[i]) { for (i = 0; i < video->uvc_num_requests; ++i) {
usb_ep_free_request(video->ep, video->req[i]); if (video->ureq[i].req) {
video->req[i] = NULL; usb_ep_free_request(video->ep, video->ureq[i].req);
video->ureq[i].req = NULL;
} }
if (video->req_buffer[i]) { if (video->ureq[i].req_buffer) {
kfree(video->req_buffer[i]); kfree(video->ureq[i].req_buffer);
video->req_buffer[i] = NULL; video->ureq[i].req_buffer = NULL;
} }
} }
kfree(video->ureq);
video->ureq = NULL;
}
INIT_LIST_HEAD(&video->req_free); INIT_LIST_HEAD(&video->req_free);
video->req_size = 0; video->req_size = 0;
return 0; return 0;
@ -207,21 +213,26 @@ uvc_video_alloc_requests(struct uvc_video *video)
* max_t(unsigned int, video->ep->maxburst, 1) * max_t(unsigned int, video->ep->maxburst, 1)
* (video->ep->mult); * (video->ep->mult);
for (i = 0; i < UVC_NUM_REQUESTS; ++i) { video->ureq = kcalloc(video->uvc_num_requests, sizeof(struct uvc_request), GFP_KERNEL);
video->req_buffer[i] = kmalloc(req_size, GFP_KERNEL); if (video->ureq == NULL)
if (video->req_buffer[i] == 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; goto error;
video->req[i] = usb_ep_alloc_request(video->ep, GFP_KERNEL); video->ureq[i].req = usb_ep_alloc_request(video->ep, GFP_KERNEL);
if (video->req[i] == NULL) if (video->ureq[i].req == NULL)
goto error; goto error;
video->req[i]->buf = video->req_buffer[i]; video->ureq[i].req->buf = video->ureq[i].req_buffer;
video->req[i]->length = 0; video->ureq[i].req->length = 0;
video->req[i]->complete = uvc_video_complete; video->ureq[i].req->complete = uvc_video_complete;
video->req[i]->context = video; 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; video->req_size = req_size;
@ -312,9 +323,9 @@ int uvcg_video_enable(struct uvc_video *video, int enable)
cancel_work_sync(&video->pump); cancel_work_sync(&video->pump);
uvcg_queue_cancel(&video->queue, 0); uvcg_queue_cancel(&video->queue, 0);
for (i = 0; i < UVC_NUM_REQUESTS; ++i) for (i = 0; i < video->uvc_num_requests; ++i)
if (video->req[i]) if (video->ureq && video->ureq[i].req)
usb_ep_dequeue(video->ep, video->req[i]); usb_ep_dequeue(video->ep, video->ureq[i].req);
uvc_video_free_requests(video); uvc_video_free_requests(video);
uvcg_queue_enable(&video->queue, 0); uvcg_queue_enable(&video->queue, 0);