From c2343663850d8931f75a7dfe4317c62732c6fce1 Mon Sep 17 00:00:00 2001 From: Andy Walls Date: Sat, 15 Nov 2008 23:38:19 -0500 Subject: cx18: Major rewrite of interrupt handling for incoming mailbox processing From: Andy Walls A major rewrite of interrupt handling for incoming mailbox processing, to split the timing critical steps from the the deferrable steps as the sending XPU on the CX23418 will time out and overwrite our incoming mailboxes rather quickly. Setup a pool of work "order forms" for the irq handler to send jobs to the new work handler routine which uses the kernel default work queue to do the deferrable work. Started optimizing some of the cx18-io calls as they are now the low hanging fruit for recoving microseconds back from the timeline. Future optimizations will get rid of mmio read retries, mmio stats logging, and combine smaller functions in the irq path into the larger ones to save ~2 us each. Priority: normal Signed-off-by: Andy Walls --- linux/drivers/media/video/cx18/cx18-queue.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) (limited to 'linux/drivers/media/video/cx18/cx18-queue.c') diff --git a/linux/drivers/media/video/cx18/cx18-queue.c b/linux/drivers/media/video/cx18/cx18-queue.c index 174682c25..c5a81aed6 100644 --- a/linux/drivers/media/video/cx18/cx18-queue.c +++ b/linux/drivers/media/video/cx18/cx18-queue.c @@ -75,30 +75,37 @@ struct cx18_buffer *cx18_dequeue(struct cx18_stream *s, struct cx18_queue *q) return buf; } -struct cx18_buffer *cx18_queue_get_buf_irq(struct cx18_stream *s, u32 id, +struct cx18_buffer *cx18_queue_get_buf(struct cx18_stream *s, u32 id, u32 bytesused) { struct cx18 *cx = s->cx; struct list_head *p; + unsigned long flags = 0; - spin_lock(&s->qlock); + spin_lock_irqsave(&s->qlock, flags); list_for_each(p, &s->q_free.list) { struct cx18_buffer *buf = list_entry(p, struct cx18_buffer, list); - if (buf->id != id) + if (buf->id != id) { + CX18_DEBUG_HI_DMA("Skipping buffer %d searching for %d " + "in stream %s q_free\n", buf->id, id, + s->name); continue; + } buf->bytesused = bytesused; - 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); + 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); + } - spin_unlock(&s->qlock); + spin_unlock_irqrestore(&s->qlock, flags); return buf; } - spin_unlock(&s->qlock); + spin_unlock_irqrestore(&s->qlock, flags); CX18_ERR("Cannot find buffer %d for stream %s\n", id, s->name); return NULL; } -- cgit v1.2.3 From 89619141828f0acac90a00d469d4458672624cd8 Mon Sep 17 00:00:00 2001 From: Andy Walls Date: Sun, 16 Nov 2008 18:18:05 -0500 Subject: cx18: Convert per stream queue spinlocks into mutexes From: Andy Walls Convert the per stream queue spinlocks into mutexes. All queue manipulation happens via the work queue or system calls into the driver, and not in an interrupt context. This reduces the amout of time the cx18 driver keeps interrupts disabled. Priority: normal Signed-off-by: Andy Walls --- linux/drivers/media/video/cx18/cx18-queue.c | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) (limited to 'linux/drivers/media/video/cx18/cx18-queue.c') diff --git a/linux/drivers/media/video/cx18/cx18-queue.c b/linux/drivers/media/video/cx18/cx18-queue.c index c5a81aed6..5a3839403 100644 --- a/linux/drivers/media/video/cx18/cx18-queue.c +++ b/linux/drivers/media/video/cx18/cx18-queue.c @@ -44,34 +44,31 @@ void cx18_queue_init(struct cx18_queue *q) void cx18_enqueue(struct cx18_stream *s, struct cx18_buffer *buf, struct cx18_queue *q) { - unsigned long flags = 0; - /* clear the buffer if it is going to be enqueued to the free queue */ if (q == &s->q_free) { buf->bytesused = 0; buf->readpos = 0; buf->b_flags = 0; } - spin_lock_irqsave(&s->qlock, flags); + mutex_lock(&s->qlock); list_add_tail(&buf->list, &q->list); atomic_inc(&q->buffers); q->bytesused += buf->bytesused - buf->readpos; - spin_unlock_irqrestore(&s->qlock, flags); + mutex_unlock(&s->qlock); } struct cx18_buffer *cx18_dequeue(struct cx18_stream *s, struct cx18_queue *q) { struct cx18_buffer *buf = NULL; - unsigned long flags = 0; - spin_lock_irqsave(&s->qlock, flags); + mutex_lock(&s->qlock); if (!list_empty(&q->list)) { buf = list_entry(q->list.next, struct cx18_buffer, list); list_del_init(q->list.next); atomic_dec(&q->buffers); q->bytesused -= buf->bytesused - buf->readpos; } - spin_unlock_irqrestore(&s->qlock, flags); + mutex_unlock(&s->qlock); return buf; } @@ -80,9 +77,8 @@ struct cx18_buffer *cx18_queue_get_buf(struct cx18_stream *s, u32 id, { struct cx18 *cx = s->cx; struct list_head *p; - unsigned long flags = 0; - spin_lock_irqsave(&s->qlock, flags); + mutex_lock(&s->qlock); list_for_each(p, &s->q_free.list) { struct cx18_buffer *buf = list_entry(p, struct cx18_buffer, list); @@ -102,10 +98,10 @@ struct cx18_buffer *cx18_queue_get_buf(struct cx18_stream *s, u32 id, list_move_tail(&buf->list, &s->q_full.list); } - spin_unlock_irqrestore(&s->qlock, flags); + mutex_unlock(&s->qlock); return buf; } - spin_unlock_irqrestore(&s->qlock, flags); + mutex_unlock(&s->qlock); CX18_ERR("Cannot find buffer %d for stream %s\n", id, s->name); return NULL; } @@ -113,13 +109,12 @@ struct cx18_buffer *cx18_queue_get_buf(struct cx18_stream *s, u32 id, /* Move all buffers of a queue to q_free, while flushing the buffers */ static void cx18_queue_flush(struct cx18_stream *s, struct cx18_queue *q) { - unsigned long flags; struct cx18_buffer *buf; if (q == &s->q_free) return; - spin_lock_irqsave(&s->qlock, flags); + mutex_lock(&s->qlock); while (!list_empty(&q->list)) { buf = list_entry(q->list.next, struct cx18_buffer, list); list_move_tail(q->list.next, &s->q_free.list); @@ -127,7 +122,7 @@ static void cx18_queue_flush(struct cx18_stream *s, struct cx18_queue *q) atomic_inc(&s->q_free.buffers); } cx18_queue_init(q); - spin_unlock_irqrestore(&s->qlock, flags); + mutex_unlock(&s->qlock); } void cx18_flush_queues(struct cx18_stream *s) -- cgit v1.2.3 From ab836bf8e5b5007ce7e1e2e6513637e99fea6a83 Mon Sep 17 00:00:00 2001 From: Andy Walls Date: Tue, 18 Nov 2008 23:24:33 -0500 Subject: cx18: Restore buffers that have fallen out of the transfer rotation From: Andy Walls Restore buffers that have fallen out of the transfer rotation, and check for coherent mailbox data when processing a stale mailbox. Priority: normal Signed-off-by: Andy Walls --- linux/drivers/media/video/cx18/cx18-queue.c | 59 ++++++++++++++++++++++------- 1 file changed, 45 insertions(+), 14 deletions(-) (limited to 'linux/drivers/media/video/cx18/cx18-queue.c') diff --git a/linux/drivers/media/video/cx18/cx18-queue.c b/linux/drivers/media/video/cx18/cx18-queue.c index 5a3839403..ff6df3632 100644 --- a/linux/drivers/media/video/cx18/cx18-queue.c +++ b/linux/drivers/media/video/cx18/cx18-queue.c @@ -49,6 +49,7 @@ void cx18_enqueue(struct cx18_stream *s, struct cx18_buffer *buf, buf->bytesused = 0; buf->readpos = 0; buf->b_flags = 0; + buf->skipped = 0; } mutex_lock(&s->qlock); list_add_tail(&buf->list, &q->list); @@ -67,6 +68,7 @@ struct cx18_buffer *cx18_dequeue(struct cx18_stream *s, struct cx18_queue *q) list_del_init(q->list.next); atomic_dec(&q->buffers); q->bytesused -= buf->bytesused - buf->readpos; + buf->skipped = 0; } mutex_unlock(&s->qlock); return buf; @@ -76,34 +78,63 @@ struct cx18_buffer *cx18_queue_get_buf(struct cx18_stream *s, u32 id, u32 bytesused) { struct cx18 *cx = s->cx; - struct list_head *p; + struct cx18_buffer *buf; + struct cx18_buffer *ret = NULL; + struct list_head *p, *t; + LIST_HEAD(r); mutex_lock(&s->qlock); - list_for_each(p, &s->q_free.list) { - struct cx18_buffer *buf = - list_entry(p, struct cx18_buffer, list); + list_for_each_safe(p, t, &s->q_free.list) { + buf = list_entry(p, struct cx18_buffer, list); if (buf->id != id) { - CX18_DEBUG_HI_DMA("Skipping buffer %d searching for %d " - "in stream %s q_free\n", buf->id, id, - s->name); + buf->skipped++; + if (buf->skipped >= atomic_read(&s->q_free.buffers)-1) { + /* buffer must have fallen out of rotation */ + atomic_dec(&s->q_free.buffers); + list_move_tail(&buf->list, &r); + CX18_WARN("Skipped %s, buffer %d, %d " + "times - it must have dropped out of " + "rotation\n", s->name, buf->id, + buf->skipped); + } continue; } buf->bytesused = bytesused; - if (s->type != CX18_ENC_STREAM_TYPE_TS) { - atomic_dec(&s->q_free.buffers); + atomic_dec(&s->q_free.buffers); + if (s->type == CX18_ENC_STREAM_TYPE_TS) { + /* + * TS doesn't use q_full, but for sweeping up lost + * buffers, we want the TS to requeue the buffer just + * before sending the MDL back to the firmware, so we + * pull it off the list here. + */ + list_del_init(&buf->list); + } else { atomic_inc(&s->q_full.buffers); s->q_full.bytesused += buf->bytesused; list_move_tail(&buf->list, &s->q_full.list); } - mutex_unlock(&s->qlock); - return buf; + ret = buf; + break; } mutex_unlock(&s->qlock); - CX18_ERR("Cannot find buffer %d for stream %s\n", id, s->name); - return NULL; + + /* Put lost buffers back into firmware transfer rotation */ + while (!list_empty(&r)) { + buf = list_entry(r.next, struct cx18_buffer, list); + list_del_init(r.next); + cx18_enqueue(s, buf, &s->q_free); + 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); + CX18_INFO("Returning %s, buffer %d back to transfer rotation\n", + s->name, buf->id); + /* and there was much rejoicing... */ + } + return ret; } /* Move all buffers of a queue to q_free, while flushing the buffers */ @@ -118,7 +149,7 @@ static void cx18_queue_flush(struct cx18_stream *s, struct cx18_queue *q) while (!list_empty(&q->list)) { buf = list_entry(q->list.next, struct cx18_buffer, list); list_move_tail(q->list.next, &s->q_free.list); - buf->bytesused = buf->readpos = buf->b_flags = 0; + buf->bytesused = buf->readpos = buf->b_flags = buf->skipped = 0; atomic_inc(&s->q_free.buffers); } cx18_queue_init(q); -- cgit v1.2.3 From 7dacf773190ee5feda4783ac5106b4c7ad031ffb Mon Sep 17 00:00:00 2001 From: Andy Walls Date: Fri, 21 Nov 2008 23:37:34 -0500 Subject: cx18: Copyright attribution update for files modified by awalls From: Andy Walls Add copyright attribution for files modified by awalls in 2008 Priority: normal Signed-off-by: Andy Walls --- linux/drivers/media/video/cx18/cx18-queue.c | 1 + 1 file changed, 1 insertion(+) (limited to 'linux/drivers/media/video/cx18/cx18-queue.c') diff --git a/linux/drivers/media/video/cx18/cx18-queue.c b/linux/drivers/media/video/cx18/cx18-queue.c index ff6df3632..7b09c9a3e 100644 --- a/linux/drivers/media/video/cx18/cx18-queue.c +++ b/linux/drivers/media/video/cx18/cx18-queue.c @@ -4,6 +4,7 @@ * Derived from ivtv-queue.c * * Copyright (C) 2007 Hans Verkuil + * Copyright (C) 2008 Andy Walls * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by -- cgit v1.2.3