Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

usb: gadget: uvc: queue empty isoc requests if no video buffer is available

ISOC transfers expect a certain cadence of requests being queued. Not
keeping up with the expected rate of requests results in missed ISOC
transfers (EXDEV). The application layer may or may not produce video
frames to match this expectation, so uvc gadget driver must handle cases
where the application is not queuing up buffers fast enough to fulfill
ISOC requirements.

Currently, uvc gadget driver waits for new video buffer to become available
before queuing up usb requests. With this patch the gadget driver queues up
0 length usb requests whenever there are no video buffers available. The
USB controller's complete callback is used as the limiter for how quickly
the 0 length packets will be queued. Video buffers are still queued as
soon as they become available.

Link: https://lore.kernel.org/CAMHf4WKbi6KBPQztj9FA4kPvESc1fVKrC8G73-cs6tTeQby9=w@mail.gmail.com/
Signed-off-by: Avichal Rakesh <arakesh@google.com>
Link: https://lore.kernel.org/r/20230508231103.1621375-1-arakesh@google.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Avichal Rakesh and committed by
Greg Kroah-Hartman
c3ff12a9 e5990469

+24 -8
+24 -8
drivers/usb/gadget/function/uvc_video.c
··· 386 386 struct uvc_buffer *buf; 387 387 unsigned long flags; 388 388 int ret; 389 + bool buf_int; 390 + /* video->max_payload_size is only set when using bulk transfer */ 391 + bool is_bulk = video->max_payload_size; 389 392 390 393 while (video->ep->enabled) { 391 394 /* ··· 411 408 */ 412 409 spin_lock_irqsave(&queue->irqlock, flags); 413 410 buf = uvcg_queue_head(queue); 414 - if (buf == NULL) { 411 + 412 + if (buf != NULL) { 413 + video->encode(req, video, buf); 414 + /* Always interrupt for the last request of a video buffer */ 415 + buf_int = buf->state == UVC_BUF_STATE_DONE; 416 + } else if (!(queue->flags & UVC_QUEUE_DISCONNECTED) && !is_bulk) { 417 + /* 418 + * No video buffer available; the queue is still connected and 419 + * we're traferring over ISOC. Queue a 0 length request to 420 + * prevent missed ISOC transfers. 421 + */ 422 + req->length = 0; 423 + buf_int = false; 424 + } else { 425 + /* 426 + * Either queue has been disconnected or no video buffer 427 + * available to bulk transfer. Either way, stop processing 428 + * further. 429 + */ 415 430 spin_unlock_irqrestore(&queue->irqlock, flags); 416 431 break; 417 432 } 418 - 419 - video->encode(req, video, buf); 420 433 421 434 /* 422 435 * With usb3 we have more requests. This will decrease the 423 436 * interrupt load to a quarter but also catches the corner 424 437 * cases, which needs to be handled. 425 438 */ 426 - if (list_empty(&video->req_free) || 427 - buf->state == UVC_BUF_STATE_DONE || 439 + if (list_empty(&video->req_free) || buf_int || 428 440 !(video->req_int_count % 429 441 DIV_ROUND_UP(video->uvc_num_requests, 4))) { 430 442 video->req_int_count = 0; ··· 459 441 460 442 /* Endpoint now owns the request */ 461 443 req = NULL; 462 - if (buf->state != UVC_BUF_STATE_DONE) 463 - video->req_int_count++; 444 + video->req_int_count++; 464 445 } 465 446 466 447 if (!req) ··· 544 527 V4L2_BUF_TYPE_VIDEO_OUTPUT, &video->mutex); 545 528 return 0; 546 529 } 547 -