summary refs log tree commit diff
diff options
context:
space:
mode:
authorAndy Walls <awalls@radix.net>2008-11-05 00:49:14 -0300
committerMauro Carvalho Chehab <mchehab@redhat.com>2008-11-11 08:11:33 -0200
commit1d6782bda5c1fb2bca44af50647b45427d8ef4ec (patch)
tree11cc68f4410ca4850ff3d874900f628ed9326064
parentc9ff1b689a5d605640f098afc37d6102ecef9876 (diff)
downloadlinux-1d6782bda5c1fb2bca44af50647b45427d8ef4ec.tar.gz
V4L/DVB (9516): cx18: Move DVB buffer transfer handling from irq handler to work_queue
cx18: Move DVB buffer transfer handling from irq handler to work_queue thread.
In order to properly lock the epu2cpu mailbox for driver to CX23418 commands,
the DVB/TS buffer handling needs to be moved from the IRQ handler and IRQ
context to a work queue.  This work_queue implmentation is strikingly similar
to the ivtv implementation - for better or worse.

Signed-off-by: Andy Walls <awalls@radix.net>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r--drivers/media/video/cx18/cx18-driver.c12
-rw-r--r--drivers/media/video/cx18/cx18-driver.h18
-rw-r--r--drivers/media/video/cx18/cx18-dvb.c23
-rw-r--r--drivers/media/video/cx18/cx18-dvb.h1
-rw-r--r--drivers/media/video/cx18/cx18-irq.c29
-rw-r--r--drivers/media/video/cx18/cx18-irq.h4
-rw-r--r--drivers/media/video/cx18/cx18-queue.c14
7 files changed, 75 insertions, 26 deletions
diff --git a/drivers/media/video/cx18/cx18-driver.c b/drivers/media/video/cx18/cx18-driver.c
index 2befa3819cdb..7874d9790a51 100644
--- a/drivers/media/video/cx18/cx18-driver.c
+++ b/drivers/media/video/cx18/cx18-driver.c
@@ -449,6 +449,14 @@ static int __devinit cx18_init_struct1(struct cx18 *cx)
 
 	spin_lock_init(&cx->lock);
 
+	cx->work_queue = create_singlethread_workqueue(cx->name);
+	if (cx->work_queue == NULL) {
+		CX18_ERR("Could not create work queue\n");
+		return -1;
+	}
+
+	INIT_WORK(&cx->work, cx18_work_handler);
+
 	/* start counting open_id at 1 */
 	cx->open_id = 1;
 
@@ -831,6 +839,7 @@ free_map:
 free_mem:
 	release_mem_region(cx->base_addr, CX18_MEM_SIZE);
 free_workqueue:
+	destroy_workqueue(cx->work_queue);
 err:
 	if (retval == 0)
 		retval = -ENODEV;
@@ -931,6 +940,9 @@ static void cx18_remove(struct pci_dev *pci_dev)
 
 	cx18_halt_firmware(cx);
 
+	flush_workqueue(cx->work_queue);
+	destroy_workqueue(cx->work_queue);
+
 	cx18_streams_cleanup(cx, 1);
 
 	exit_cx18_i2c(cx);
diff --git a/drivers/media/video/cx18/cx18-driver.h b/drivers/media/video/cx18/cx18-driver.h
index e721c01d2178..bbdd5f25041d 100644
--- a/drivers/media/video/cx18/cx18-driver.h
+++ b/drivers/media/video/cx18/cx18-driver.h
@@ -199,12 +199,15 @@ struct cx18_options {
 #define CX18_F_S_APPL_IO        8	/* this stream is used read/written by an application */
 
 /* per-cx18, i_flags */
-#define CX18_F_I_LOADED_FW	0 	/* Loaded the firmware the first time */
-#define CX18_F_I_EOS		4 	/* End of encoder stream reached */
-#define CX18_F_I_RADIO_USER	5 	/* The radio tuner is selected */
-#define CX18_F_I_ENC_PAUSED	13 	/* the encoder is paused */
-#define CX18_F_I_INITED		21 	/* set after first open */
-#define CX18_F_I_FAILED		22 	/* set if first open failed */
+#define CX18_F_I_LOADED_FW		0 	/* Loaded firmware 1st time */
+#define CX18_F_I_EOS			4 	/* End of encoder stream */
+#define CX18_F_I_RADIO_USER		5 	/* radio tuner is selected */
+#define CX18_F_I_ENC_PAUSED		13 	/* the encoder is paused */
+#define CX18_F_I_HAVE_WORK		15   	/* there is work to be done */
+#define CX18_F_I_WORK_HANDLER_DVB	18   	/* work to be done for DVB */
+#define CX18_F_I_INITED			21 	/* set after first open */
+#define CX18_F_I_FAILED			22 	/* set if first open failed */
+#define CX18_F_I_WORK_INITED		23	/* worker thread initialized */
 
 /* These are the VBI types as they appear in the embedded VBI private packets. */
 #define CX18_SLICED_TYPE_TELETEXT_B     (1)
@@ -431,6 +434,9 @@ struct cx18 {
 	/* when the current DMA is finished this queue is woken up */
 	wait_queue_head_t dma_waitq;
 
+	struct workqueue_struct *work_queue;
+	struct work_struct work;
+
 	/* i2c */
 	struct i2c_adapter i2c_adap[2];
 	struct i2c_algo_bit_data i2c_algo[2];
diff --git a/drivers/media/video/cx18/cx18-dvb.c b/drivers/media/video/cx18/cx18-dvb.c
index afc694e7bdb2..4542e2e5e3d7 100644
--- a/drivers/media/video/cx18/cx18-dvb.c
+++ b/drivers/media/video/cx18/cx18-dvb.c
@@ -23,6 +23,8 @@
 #include "cx18-dvb.h"
 #include "cx18-io.h"
 #include "cx18-streams.h"
+#include "cx18-queue.h"
+#include "cx18-scb.h"
 #include "cx18-cards.h"
 #include "s5h1409.h"
 #include "mxl5005s.h"
@@ -300,3 +302,24 @@ static int dvb_register(struct cx18_stream *stream)
 
 	return ret;
 }
+
+void cx18_dvb_work_handler(struct cx18 *cx)
+{
+	struct cx18_buffer *buf;
+	struct cx18_stream *s = &cx->streams[CX18_ENC_STREAM_TYPE_TS];
+
+	while ((buf = cx18_dequeue(s, &s->q_full)) != NULL) {
+		if (s->dvb.enabled)
+			dvb_dmx_swfilter(&s->dvb.demux, buf->buf,
+					 buf->bytesused);
+
+		cx18_enqueue(s, buf, &s->q_free);
+		cx18_buf_sync_for_device(s, buf);
+		if (s->handle == CX18_INVALID_TASK_HANDLE) /* FIXME: improve */
+			continue;
+
+		cx18_vapi(cx, CX18_CPU_DE_SET_MDL, 5, s->handle,
+		       (void __iomem *)&cx->scb->cpu_mdl[buf->id] - cx->enc_mem,
+		       1, buf->id, s->buf_size);
+	}
+}
diff --git a/drivers/media/video/cx18/cx18-dvb.h b/drivers/media/video/cx18/cx18-dvb.h
index bf8d8f6f5455..bbdcefc87f28 100644
--- a/drivers/media/video/cx18/cx18-dvb.h
+++ b/drivers/media/video/cx18/cx18-dvb.h
@@ -23,3 +23,4 @@
 
 int cx18_dvb_register(struct cx18_stream *stream);
 void cx18_dvb_unregister(struct cx18_stream *stream);
+void cx18_dvb_work_handler(struct cx18 *cx);
diff --git a/drivers/media/video/cx18/cx18-irq.c b/drivers/media/video/cx18/cx18-irq.c
index c306e142c1c3..5fbfbd0f1493 100644
--- a/drivers/media/video/cx18/cx18-irq.c
+++ b/drivers/media/video/cx18/cx18-irq.c
@@ -29,6 +29,20 @@
 #include "cx18-mailbox.h"
 #include "cx18-vbi.h"
 #include "cx18-scb.h"
+#include "cx18-dvb.h"
+
+void cx18_work_handler(struct work_struct *work)
+{
+	struct cx18 *cx = container_of(work, struct cx18, work);
+	if (test_and_clear_bit(CX18_F_I_WORK_INITED, &cx->i_flags)) {
+		struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 };
+		/* This thread must use the FIFO scheduler as it
+		 * is realtime sensitive. */
+		sched_setscheduler(current, SCHED_FIFO, &param);
+	}
+	if (test_and_clear_bit(CX18_F_I_WORK_HANDLER_DVB, &cx->i_flags))
+		cx18_dvb_work_handler(cx);
+}
 
 static void epu_dma_done(struct cx18 *cx, struct cx18_mailbox *mb)
 {
@@ -65,17 +79,11 @@ static void epu_dma_done(struct cx18 *cx, struct cx18_mailbox *mb)
 	if (buf) {
 		cx18_buf_sync_for_cpu(s, buf);
 		if (s->type == CX18_ENC_STREAM_TYPE_TS && s->dvb.enabled) {
-			/* process the buffer here */
-			CX18_DEBUG_HI_DMA("TS recv and sent bytesused=%d\n",
+			CX18_DEBUG_HI_DMA("TS recv bytesused = %d\n",
 					buf->bytesused);
 
-			dvb_dmx_swfilter(&s->dvb.demux, buf->buf,
-					buf->bytesused);
-
-			cx18_buf_sync_for_device(s, buf);
-			cx18_vapi(cx, CX18_CPU_DE_SET_MDL, 5, s->handle,
-			    (void __iomem *)&cx->scb->cpu_mdl[buf->id] - cx->enc_mem,
-			    1, buf->id, s->buf_size);
+			set_bit(CX18_F_I_WORK_HANDLER_DVB, &cx->i_flags);
+			set_bit(CX18_F_I_HAVE_WORK, &cx->i_flags);
 		} else
 			set_bit(CX18_F_B_NEED_BUF_SWAP, &buf->b_flags);
 	} else {
@@ -185,5 +193,8 @@ irqreturn_t cx18_irq_handler(int irq, void *dev_id)
 	if (sw1)
 		epu_cmd(cx, sw1);
 
+	if (test_and_clear_bit(CX18_F_I_HAVE_WORK, &cx->i_flags))
+		queue_work(cx->work_queue, &cx->work);
+
 	return (sw1 || sw2 || hw2) ? IRQ_HANDLED : IRQ_NONE;
 }
diff --git a/drivers/media/video/cx18/cx18-irq.h b/drivers/media/video/cx18/cx18-irq.h
index 379f704f5cba..6173ca3bc9e4 100644
--- a/drivers/media/video/cx18/cx18-irq.h
+++ b/drivers/media/video/cx18/cx18-irq.h
@@ -32,6 +32,4 @@
 
 irqreturn_t cx18_irq_handler(int irq, void *dev_id);
 
-void cx18_irq_work_handler(struct work_struct *work);
-void cx18_dma_stream_dec_prepare(struct cx18_stream *s, u32 offset, int lock);
-void cx18_unfinished_dma(unsigned long arg);
+void cx18_work_handler(struct work_struct *work);
diff --git a/drivers/media/video/cx18/cx18-queue.c b/drivers/media/video/cx18/cx18-queue.c
index a33ba04a2686..174682c2582f 100644
--- a/drivers/media/video/cx18/cx18-queue.c
+++ b/drivers/media/video/cx18/cx18-queue.c
@@ -88,15 +88,13 @@ struct cx18_buffer *cx18_queue_get_buf_irq(struct cx18_stream *s, u32 id,
 
 		if (buf->id != id)
 			continue;
+
 		buf->bytesused = bytesused;
-		/* the transport buffers are handled differently,
-		   they are not moved to the full queue */
-		if (s->type != CX18_ENC_STREAM_TYPE_TS) {
-			atomic_dec(&s->q_free.buffers);
-			atomic_inc(&s->q_full.buffers);
-			s->q_full.bytesused += buf->bytesused;
-			list_move_tail(&buf->list, &s->q_full.list);
-		}
+		atomic_dec(&s->q_free.buffers);
+		atomic_inc(&s->q_full.buffers);
+		s->q_full.bytesused += buf->bytesused;
+		list_move_tail(&buf->list, &s->q_full.list);
+
 		spin_unlock(&s->qlock);
 		return buf;
 	}