From 87116159517ecf6b9cf62a136f2935a63833c485 Mon Sep 17 00:00:00 2001
From: Andy Walls <awalls@radix.net>
Date: Mon, 13 Apr 2009 22:42:43 -0300
Subject: 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>
---
 drivers/media/video/cx18/cx18-driver.h | 32 ++++++++++++++++++++++++++++++++
 1 file changed, 32 insertions(+)

(limited to 'drivers/media/video/cx18/cx18-driver.h')

diff --git a/drivers/media/video/cx18/cx18-driver.h b/drivers/media/video/cx18/cx18-driver.h
index e6f42d0..62dca43 100644
--- a/drivers/media/video/cx18/cx18-driver.h
+++ b/drivers/media/video/cx18/cx18-driver.h
@@ -254,6 +254,7 @@ struct cx18_options {
 #define CX18_F_S_INTERNAL_USE	5	/* this stream is used internally (sliced VBI processing) */
 #define CX18_F_S_STREAMOFF	7	/* signal end of stream EOS */
 #define CX18_F_S_APPL_IO        8	/* this stream is used read/written by an application */
+#define CX18_F_S_STOPPING	9	/* telling the fw to stop capturing */
 
 /* per-cx18, i_flags */
 #define CX18_F_I_LOADED_FW		0 	/* Loaded firmware 1st time */
@@ -324,6 +325,33 @@ struct cx18_in_work_order {
 	char *str;
 };
 
+/*
+ * There are 2 types of deferrable tasks that send messages out to the firmware:
+ * 1. Sending individual buffers back to the firmware
+ * 2. Sending as many free buffers for a stream from q_free as we can to the fw
+ *
+ * The worst case scenario for multiple simultaneous streams is
+ * TS, YUV, PCM, VBI, MPEG, and IDX all going at once.
+ *
+ * We try to load the firmware queue with as many free buffers as possible,
+ * whenever we get a buffer back for a stream.  For the TS we return the single
+ * buffer to the firmware at that time as well.  For all other streams, we
+ * return single buffers to the firmware as the application drains them.
+ *
+ * 6 streams * 2 sets of orders * (1 single buf + 1 load fw from q_free)
+ * = 24 work orders should cover our needs, provided the applications read
+ * at a fairly steady rate.  If apps don't, we fall back to non-deferred
+ * operation, when no cx18_out_work_orders are available for use.
+ */
+#define CX18_MAX_OUT_WORK_ORDERS (24)
+
+struct cx18_out_work_order {
+	struct work_struct work;
+	atomic_t pending;
+	struct cx18_stream *s;
+	struct cx18_buffer *buf; /* buf == NULL, means load fw from q_free */
+};
+
 #define CX18_INVALID_TASK_HANDLE 0xffffffff
 
 struct cx18_stream {
@@ -573,6 +601,10 @@ struct cx18 {
 	struct cx18_in_work_order in_work_order[CX18_MAX_IN_WORK_ORDERS];
 	char epu_debug_str[256]; /* CX18_EPU_DEBUG is rare: use shared space */
 
+	struct workqueue_struct *out_work_queue;
+	char out_workq_name[12]; /* "cx18-NN-out" */
+	struct cx18_out_work_order out_work_order[CX18_MAX_OUT_WORK_ORDERS];
+
 	/* i2c */
 	struct i2c_adapter i2c_adap[2];
 	struct i2c_algo_bit_data i2c_algo[2];
-- 
cgit v1.1