aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/cx18/cx18-streams.c
diff options
context:
space:
mode:
authorAndy Walls <awalls@radix.net>2009-04-13 21:42:43 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2009-06-16 17:20:44 -0400
commit87116159517ecf6b9cf62a136f2935a63833c485 (patch)
tree4a52a97e9e740304ed44d4348762836284f4d100 /drivers/media/video/cx18/cx18-streams.c
parentdeed75ed9f7576ada4bca02e6c851833a352a38d (diff)
V4L/DVB (11616): cx18: Add a work queue for deferring empty buffer handoffs to the firmware
This change defers sending all CX18_CPU_DE_SET_MDL commands, for a stream with an ongoing capture, by adding a work queue to handle sending such commands when needed. This prevents any sleeps, caused by notifying the firmware of new usable buffers, when a V4L2 application read() is being satisfied or when an incoming buffer is processed by the cx18-NN-in work queue thread. Signed-off-by: Andy Walls <awalls@radix.net> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/cx18/cx18-streams.c')
-rw-r--r--drivers/media/video/cx18/cx18-streams.c99
1 files changed, 94 insertions, 5 deletions
diff --git a/drivers/media/video/cx18/cx18-streams.c b/drivers/media/video/cx18/cx18-streams.c
index 0932b76b2373..bbeb01c5cf32 100644
--- a/drivers/media/video/cx18/cx18-streams.c
+++ b/drivers/media/video/cx18/cx18-streams.c
@@ -431,14 +431,16 @@ static void cx18_vbi_setup(struct cx18_stream *s)
431 cx18_api(cx, CX18_CPU_SET_RAW_VBI_PARAM, 6, data); 431 cx18_api(cx, CX18_CPU_SET_RAW_VBI_PARAM, 6, data);
432} 432}
433 433
434struct cx18_queue *cx18_stream_put_buf_fw(struct cx18_stream *s, 434static
435 struct cx18_buffer *buf) 435struct cx18_queue *_cx18_stream_put_buf_fw(struct cx18_stream *s,
436 struct cx18_buffer *buf)
436{ 437{
437 struct cx18 *cx = s->cx; 438 struct cx18 *cx = s->cx;
438 struct cx18_queue *q; 439 struct cx18_queue *q;
439 440
440 /* Don't give it to the firmware, if we're not running a capture */ 441 /* Don't give it to the firmware, if we're not running a capture */
441 if (s->handle == CX18_INVALID_TASK_HANDLE || 442 if (s->handle == CX18_INVALID_TASK_HANDLE ||
443 test_bit(CX18_F_S_STOPPING, &s->s_flags) ||
442 !test_bit(CX18_F_S_STREAMING, &s->s_flags)) 444 !test_bit(CX18_F_S_STREAMING, &s->s_flags))
443 return cx18_enqueue(s, buf, &s->q_free); 445 return cx18_enqueue(s, buf, &s->q_free);
444 446
@@ -453,7 +455,8 @@ struct cx18_queue *cx18_stream_put_buf_fw(struct cx18_stream *s,
453 return q; 455 return q;
454} 456}
455 457
456void cx18_stream_load_fw_queue(struct cx18_stream *s) 458static
459void _cx18_stream_load_fw_queue(struct cx18_stream *s)
457{ 460{
458 struct cx18_queue *q; 461 struct cx18_queue *q;
459 struct cx18_buffer *buf; 462 struct cx18_buffer *buf;
@@ -467,11 +470,93 @@ void cx18_stream_load_fw_queue(struct cx18_stream *s)
467 buf = cx18_dequeue(s, &s->q_free); 470 buf = cx18_dequeue(s, &s->q_free);
468 if (buf == NULL) 471 if (buf == NULL)
469 break; 472 break;
470 q = cx18_stream_put_buf_fw(s, buf); 473 q = _cx18_stream_put_buf_fw(s, buf);
471 } while (atomic_read(&s->q_busy.buffers) < CX18_MAX_FW_MDLS_PER_STREAM 474 } while (atomic_read(&s->q_busy.buffers) < CX18_MAX_FW_MDLS_PER_STREAM
472 && q == &s->q_busy); 475 && q == &s->q_busy);
473} 476}
474 477
478static inline
479void free_out_work_order(struct cx18_out_work_order *order)
480{
481 atomic_set(&order->pending, 0);
482}
483
484void cx18_out_work_handler(struct work_struct *work)
485{
486 struct cx18_out_work_order *order =
487 container_of(work, struct cx18_out_work_order, work);
488 struct cx18_stream *s = order->s;
489 struct cx18_buffer *buf = order->buf;
490
491 free_out_work_order(order);
492
493 if (buf == NULL)
494 _cx18_stream_load_fw_queue(s);
495 else
496 _cx18_stream_put_buf_fw(s, buf);
497}
498
499static
500struct cx18_out_work_order *alloc_out_work_order(struct cx18 *cx)
501{
502 int i;
503 struct cx18_out_work_order *order = NULL;
504
505 for (i = 0; i < CX18_MAX_OUT_WORK_ORDERS; i++) {
506 /*
507 * We need "pending" to be atomic to inspect & set its contents
508 * 1. "pending" is only set to 1 here, but needs multiple access
509 * protection
510 * 2. work handler threads only clear "pending" and only
511 * on one, particular work order at a time, per handler thread.
512 */
513 if (atomic_add_unless(&cx->out_work_order[i].pending, 1, 1)) {
514 order = &cx->out_work_order[i];
515 break;
516 }
517 }
518 return order;
519}
520
521struct cx18_queue *cx18_stream_put_buf_fw(struct cx18_stream *s,
522 struct cx18_buffer *buf)
523{
524 struct cx18 *cx = s->cx;
525 struct cx18_out_work_order *order;
526
527 order = alloc_out_work_order(cx);
528 if (order == NULL) {
529 CX18_DEBUG_WARN("No blank, outgoing-mailbox, deferred-work, "
530 "order forms available; sending buffer %u back "
531 "to the firmware immediately for stream %s\n",
532 buf->id, s->name);
533 return _cx18_stream_put_buf_fw(s, buf);
534 }
535 order->s = s;
536 order->buf = buf;
537 queue_work(cx->out_work_queue, &order->work);
538 return NULL;
539}
540
541void cx18_stream_load_fw_queue(struct cx18_stream *s)
542{
543 struct cx18 *cx = s->cx;
544 struct cx18_out_work_order *order;
545
546 order = alloc_out_work_order(cx);
547 if (order == NULL) {
548 CX18_DEBUG_WARN("No blank, outgoing-mailbox, deferred-work, "
549 "order forms available; filling the firmware "
550 "buffer queue immediately for stream %s\n",
551 s->name);
552 _cx18_stream_load_fw_queue(s);
553 return;
554 }
555 order->s = s;
556 order->buf = NULL; /* Indicates to load the fw queue */
557 queue_work(cx->out_work_queue, &order->work);
558}
559
475int cx18_start_v4l2_encode_stream(struct cx18_stream *s) 560int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
476{ 561{
477 u32 data[MAX_MB_ARGUMENTS]; 562 u32 data[MAX_MB_ARGUMENTS];
@@ -607,12 +692,13 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
607 cx18_writel(cx, s->buf_size, &cx->scb->cpu_mdl[buf->id].length); 692 cx18_writel(cx, s->buf_size, &cx->scb->cpu_mdl[buf->id].length);
608 } 693 }
609 mutex_unlock(&s->qlock); 694 mutex_unlock(&s->qlock);
610 cx18_stream_load_fw_queue(s); 695 _cx18_stream_load_fw_queue(s);
611 696
612 /* begin_capture */ 697 /* begin_capture */
613 if (cx18_vapi(cx, CX18_CPU_CAPTURE_START, 1, s->handle)) { 698 if (cx18_vapi(cx, CX18_CPU_CAPTURE_START, 1, s->handle)) {
614 CX18_DEBUG_WARN("Error starting capture!\n"); 699 CX18_DEBUG_WARN("Error starting capture!\n");
615 /* Ensure we're really not capturing before releasing MDLs */ 700 /* Ensure we're really not capturing before releasing MDLs */
701 set_bit(CX18_F_S_STOPPING, &s->s_flags);
616 if (s->type == CX18_ENC_STREAM_TYPE_MPG) 702 if (s->type == CX18_ENC_STREAM_TYPE_MPG)
617 cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 2, s->handle, 1); 703 cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 2, s->handle, 1);
618 else 704 else
@@ -622,6 +708,7 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
622 cx18_vapi(cx, CX18_CPU_DE_RELEASE_MDL, 1, s->handle); 708 cx18_vapi(cx, CX18_CPU_DE_RELEASE_MDL, 1, s->handle);
623 cx18_vapi(cx, CX18_DESTROY_TASK, 1, s->handle); 709 cx18_vapi(cx, CX18_DESTROY_TASK, 1, s->handle);
624 s->handle = CX18_INVALID_TASK_HANDLE; 710 s->handle = CX18_INVALID_TASK_HANDLE;
711 clear_bit(CX18_F_S_STOPPING, &s->s_flags);
625 if (atomic_read(&cx->tot_capturing) == 0) { 712 if (atomic_read(&cx->tot_capturing) == 0) {
626 set_bit(CX18_F_I_EOS, &cx->i_flags); 713 set_bit(CX18_F_I_EOS, &cx->i_flags);
627 cx18_write_reg(cx, 5, CX18_DSP0_INTERRUPT_MASK); 714 cx18_write_reg(cx, 5, CX18_DSP0_INTERRUPT_MASK);
@@ -666,6 +753,7 @@ int cx18_stop_v4l2_encode_stream(struct cx18_stream *s, int gop_end)
666 if (atomic_read(&cx->tot_capturing) == 0) 753 if (atomic_read(&cx->tot_capturing) == 0)
667 return 0; 754 return 0;
668 755
756 set_bit(CX18_F_S_STOPPING, &s->s_flags);
669 if (s->type == CX18_ENC_STREAM_TYPE_MPG) 757 if (s->type == CX18_ENC_STREAM_TYPE_MPG)
670 cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 2, s->handle, !gop_end); 758 cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 2, s->handle, !gop_end);
671 else 759 else
@@ -689,6 +777,7 @@ int cx18_stop_v4l2_encode_stream(struct cx18_stream *s, int gop_end)
689 777
690 cx18_vapi(cx, CX18_DESTROY_TASK, 1, s->handle); 778 cx18_vapi(cx, CX18_DESTROY_TASK, 1, s->handle);
691 s->handle = CX18_INVALID_TASK_HANDLE; 779 s->handle = CX18_INVALID_TASK_HANDLE;
780 clear_bit(CX18_F_S_STOPPING, &s->s_flags);
692 781
693 if (atomic_read(&cx->tot_capturing) > 0) 782 if (atomic_read(&cx->tot_capturing) > 0)
694 return 0; 783 return 0;