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:
parent
c6e23b89a9
commit
9973772dbb
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in New Issue