Commit 9973772d authored by Michael Grzeschik's avatar Michael Grzeschik Committed by Greg Kroah-Hartman
Browse files

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: default avatarPaul Elder <paul.elder@ideasonboard.com>
Reviewed-by: default avatarLaurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: default avatarMichael Grzeschik <m.grzeschik@pengutronix.de>
Link: https://lore.kernel.org/r/20210628155311.16762-3-m.grzeschik@pengutronix.de


Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent c6e23b89
Loading
Loading
Loading
Loading
+8 −3
Original line number Diff line number Diff line
@@ -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;

+6 −0
Original line number Diff line number Diff line
@@ -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;
}

+33 −22
Original line number Diff line number Diff line
@@ -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,18 +178,23 @@ 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->req_buffer[i]) {
			kfree(video->req_buffer[i]);
			video->req_buffer[i] = NULL;
			if (video->ureq[i].req_buffer) {
				kfree(video->ureq[i].req_buffer);
				video->ureq[i].req_buffer = NULL;
			}
		}

		kfree(video->ureq);
		video->ureq = NULL;
	}

	INIT_LIST_HEAD(&video->req_free);
	video->req_size = 0;
	return 0;
@@ -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);