V4L/DVB (13429): cx18: Add Memory Descriptor List (MDL) layer to buffer handling

Add a Memory Descriptor List (MDL) layer to buffer handling to implement
scatter-gather I/O.  Currently there is still only 1 buffer per MDL.

Signed-off-by: Andy Walls <awalls@radix.net>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
diff --git a/drivers/media/video/cx18/cx18-streams.c b/drivers/media/video/cx18/cx18-streams.c
index 10228c5..9f8adda 100644
--- a/drivers/media/video/cx18/cx18-streams.c
+++ b/drivers/media/video/cx18/cx18-streams.c
@@ -115,6 +115,9 @@
 	s->dma = cx18_stream_info[type].dma;
 	s->buffers = cx->stream_buffers[type];
 	s->buf_size = cx->stream_buf_size[type];
+	INIT_LIST_HEAD(&s->buf_pool);
+	s->bufs_per_mdl = 1;
+	s->mdl_size = s->buf_size * s->bufs_per_mdl;
 
 	init_waitqueue_head(&s->waitq);
 	s->id = -1;
@@ -124,6 +127,8 @@
 	cx18_queue_init(&s->q_busy);
 	spin_lock_init(&s->q_full.lock);
 	cx18_queue_init(&s->q_full);
+	spin_lock_init(&s->q_idle.lock);
+	cx18_queue_init(&s->q_idle);
 
 	INIT_WORK(&s->out_work_order, cx18_out_work_handler);
 }
@@ -441,8 +446,8 @@
 }
 
 static
-struct cx18_queue *_cx18_stream_put_buf_fw(struct cx18_stream *s,
-					   struct cx18_buffer *buf)
+struct cx18_queue *_cx18_stream_put_mdl_fw(struct cx18_stream *s,
+					   struct cx18_mdl *mdl)
 {
 	struct cx18 *cx = s->cx;
 	struct cx18_queue *q;
@@ -451,16 +456,16 @@
 	if (s->handle == CX18_INVALID_TASK_HANDLE ||
 	    test_bit(CX18_F_S_STOPPING, &s->s_flags) ||
 	    !test_bit(CX18_F_S_STREAMING, &s->s_flags))
-		return cx18_enqueue(s, buf, &s->q_free);
+		return cx18_enqueue(s, mdl, &s->q_free);
 
-	q = cx18_enqueue(s, buf, &s->q_busy);
+	q = cx18_enqueue(s, mdl, &s->q_busy);
 	if (q != &s->q_busy)
-		return q; /* The firmware has the max buffers it can handle */
+		return q; /* The firmware has the max MDLs it can handle */
 
-	cx18_buf_sync_for_device(s, buf);
+	cx18_mdl_sync_for_device(s, mdl);
 	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);
+		  (void __iomem *) &cx->scb->cpu_mdl[mdl->id] - cx->enc_mem,
+		  s->bufs_per_mdl, mdl->id, s->mdl_size);
 	return q;
 }
 
@@ -468,7 +473,7 @@
 void _cx18_stream_load_fw_queue(struct cx18_stream *s)
 {
 	struct cx18_queue *q;
-	struct cx18_buffer *buf;
+	struct cx18_mdl *mdl;
 
 	if (atomic_read(&s->q_free.depth) == 0 ||
 	    atomic_read(&s->q_busy.depth) >= CX18_MAX_FW_MDLS_PER_STREAM)
@@ -476,10 +481,10 @@
 
 	/* Move from q_free to q_busy notifying the firmware, until the limit */
 	do {
-		buf = cx18_dequeue(s, &s->q_free);
-		if (buf == NULL)
+		mdl = cx18_dequeue(s, &s->q_free);
+		if (mdl == NULL)
 			break;
-		q = _cx18_stream_put_buf_fw(s, buf);
+		q = _cx18_stream_put_mdl_fw(s, mdl);
 	} while (atomic_read(&s->q_busy.depth) < CX18_MAX_FW_MDLS_PER_STREAM
 		 && q == &s->q_busy);
 }
@@ -492,11 +497,21 @@
 	_cx18_stream_load_fw_queue(s);
 }
 
+static void cx18_stream_configure_mdls(struct cx18_stream *s)
+{
+	cx18_unload_queues(s);
+
+	/* For now */
+	s->bufs_per_mdl = 1;
+	s->mdl_size = s->buf_size * s->bufs_per_mdl;
+
+	cx18_load_queues(s);
+}
+
 int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
 {
 	u32 data[MAX_MB_ARGUMENTS];
 	struct cx18 *cx = s->cx;
-	struct cx18_buffer *buf;
 	int captype = 0;
 	struct cx18_api_func_private priv;
 
@@ -619,14 +634,7 @@
 		(void __iomem *)&cx->scb->cpu_mdl_ack[s->type][1] - cx->enc_mem);
 
 	/* Init all the cpu_mdls for this stream */
-	cx18_flush_queues(s);
-	spin_lock(&s->q_free.lock);
-	list_for_each_entry(buf, &s->q_free.list, list) {
-		cx18_writel(cx, buf->dma_handle,
-					&cx->scb->cpu_mdl[buf->id].paddr);
-		cx18_writel(cx, s->buf_size, &cx->scb->cpu_mdl[buf->id].length);
-	}
-	spin_unlock(&s->q_free.lock);
+	cx18_stream_configure_mdls(s);
 	_cx18_stream_load_fw_queue(s);
 
 	/* begin_capture */