diff options
author | Andy Walls <awalls@radix.net> | 2008-11-18 23:24:33 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2008-12-30 06:38:10 -0500 |
commit | bca11a5721917d6d5874571813673a2669ffec4b (patch) | |
tree | a2202bdf236804a123175b12585f4aae4fdc58d7 /drivers/media/video/cx18/cx18-queue.c | |
parent | d6c7e5f8faad080e75bace5c4f2265e3513e3510 (diff) |
V4L/DVB (9726): cx18: Restore buffers that have fallen out of the transfer rotation
Restore buffers that have fallen out of the transfer rotation, and check
for coherent mailbox data when processing a stale mailbox.
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-queue.c')
-rw-r--r-- | drivers/media/video/cx18/cx18-queue.c | 59 |
1 files changed, 45 insertions, 14 deletions
diff --git a/drivers/media/video/cx18/cx18-queue.c b/drivers/media/video/cx18/cx18-queue.c index 5a3839403631..ff6df36328fd 100644 --- a/drivers/media/video/cx18/cx18-queue.c +++ b/drivers/media/video/cx18/cx18-queue.c | |||
@@ -49,6 +49,7 @@ void cx18_enqueue(struct cx18_stream *s, struct cx18_buffer *buf, | |||
49 | buf->bytesused = 0; | 49 | buf->bytesused = 0; |
50 | buf->readpos = 0; | 50 | buf->readpos = 0; |
51 | buf->b_flags = 0; | 51 | buf->b_flags = 0; |
52 | buf->skipped = 0; | ||
52 | } | 53 | } |
53 | mutex_lock(&s->qlock); | 54 | mutex_lock(&s->qlock); |
54 | list_add_tail(&buf->list, &q->list); | 55 | list_add_tail(&buf->list, &q->list); |
@@ -67,6 +68,7 @@ struct cx18_buffer *cx18_dequeue(struct cx18_stream *s, struct cx18_queue *q) | |||
67 | list_del_init(q->list.next); | 68 | list_del_init(q->list.next); |
68 | atomic_dec(&q->buffers); | 69 | atomic_dec(&q->buffers); |
69 | q->bytesused -= buf->bytesused - buf->readpos; | 70 | q->bytesused -= buf->bytesused - buf->readpos; |
71 | buf->skipped = 0; | ||
70 | } | 72 | } |
71 | mutex_unlock(&s->qlock); | 73 | mutex_unlock(&s->qlock); |
72 | return buf; | 74 | return buf; |
@@ -76,34 +78,63 @@ struct cx18_buffer *cx18_queue_get_buf(struct cx18_stream *s, u32 id, | |||
76 | u32 bytesused) | 78 | u32 bytesused) |
77 | { | 79 | { |
78 | struct cx18 *cx = s->cx; | 80 | struct cx18 *cx = s->cx; |
79 | struct list_head *p; | 81 | struct cx18_buffer *buf; |
82 | struct cx18_buffer *ret = NULL; | ||
83 | struct list_head *p, *t; | ||
84 | LIST_HEAD(r); | ||
80 | 85 | ||
81 | mutex_lock(&s->qlock); | 86 | mutex_lock(&s->qlock); |
82 | list_for_each(p, &s->q_free.list) { | 87 | list_for_each_safe(p, t, &s->q_free.list) { |
83 | struct cx18_buffer *buf = | 88 | buf = list_entry(p, struct cx18_buffer, list); |
84 | list_entry(p, struct cx18_buffer, list); | ||
85 | 89 | ||
86 | if (buf->id != id) { | 90 | if (buf->id != id) { |
87 | CX18_DEBUG_HI_DMA("Skipping buffer %d searching for %d " | 91 | buf->skipped++; |
88 | "in stream %s q_free\n", buf->id, id, | 92 | if (buf->skipped >= atomic_read(&s->q_free.buffers)-1) { |
89 | s->name); | 93 | /* buffer must have fallen out of rotation */ |
94 | atomic_dec(&s->q_free.buffers); | ||
95 | list_move_tail(&buf->list, &r); | ||
96 | CX18_WARN("Skipped %s, buffer %d, %d " | ||
97 | "times - it must have dropped out of " | ||
98 | "rotation\n", s->name, buf->id, | ||
99 | buf->skipped); | ||
100 | } | ||
90 | continue; | 101 | continue; |
91 | } | 102 | } |
92 | 103 | ||
93 | buf->bytesused = bytesused; | 104 | buf->bytesused = bytesused; |
94 | if (s->type != CX18_ENC_STREAM_TYPE_TS) { | 105 | atomic_dec(&s->q_free.buffers); |
95 | atomic_dec(&s->q_free.buffers); | 106 | if (s->type == CX18_ENC_STREAM_TYPE_TS) { |
107 | /* | ||
108 | * TS doesn't use q_full, but for sweeping up lost | ||
109 | * buffers, we want the TS to requeue the buffer just | ||
110 | * before sending the MDL back to the firmware, so we | ||
111 | * pull it off the list here. | ||
112 | */ | ||
113 | list_del_init(&buf->list); | ||
114 | } else { | ||
96 | atomic_inc(&s->q_full.buffers); | 115 | atomic_inc(&s->q_full.buffers); |
97 | s->q_full.bytesused += buf->bytesused; | 116 | s->q_full.bytesused += buf->bytesused; |
98 | list_move_tail(&buf->list, &s->q_full.list); | 117 | list_move_tail(&buf->list, &s->q_full.list); |
99 | } | 118 | } |
100 | 119 | ||
101 | mutex_unlock(&s->qlock); | 120 | ret = buf; |
102 | return buf; | 121 | break; |
103 | } | 122 | } |
104 | mutex_unlock(&s->qlock); | 123 | mutex_unlock(&s->qlock); |
105 | CX18_ERR("Cannot find buffer %d for stream %s\n", id, s->name); | 124 | |
106 | return NULL; | 125 | /* Put lost buffers back into firmware transfer rotation */ |
126 | while (!list_empty(&r)) { | ||
127 | buf = list_entry(r.next, struct cx18_buffer, list); | ||
128 | list_del_init(r.next); | ||
129 | cx18_enqueue(s, buf, &s->q_free); | ||
130 | cx18_vapi(cx, CX18_CPU_DE_SET_MDL, 5, s->handle, | ||
131 | (void __iomem *)&cx->scb->cpu_mdl[buf->id] - cx->enc_mem, | ||
132 | 1, buf->id, s->buf_size); | ||
133 | CX18_INFO("Returning %s, buffer %d back to transfer rotation\n", | ||
134 | s->name, buf->id); | ||
135 | /* and there was much rejoicing... */ | ||
136 | } | ||
137 | return ret; | ||
107 | } | 138 | } |
108 | 139 | ||
109 | /* Move all buffers of a queue to q_free, while flushing the buffers */ | 140 | /* 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) | |||
118 | while (!list_empty(&q->list)) { | 149 | while (!list_empty(&q->list)) { |
119 | buf = list_entry(q->list.next, struct cx18_buffer, list); | 150 | buf = list_entry(q->list.next, struct cx18_buffer, list); |
120 | list_move_tail(q->list.next, &s->q_free.list); | 151 | list_move_tail(q->list.next, &s->q_free.list); |
121 | buf->bytesused = buf->readpos = buf->b_flags = 0; | 152 | buf->bytesused = buf->readpos = buf->b_flags = buf->skipped = 0; |
122 | atomic_inc(&s->q_free.buffers); | 153 | atomic_inc(&s->q_free.buffers); |
123 | } | 154 | } |
124 | cx18_queue_init(q); | 155 | cx18_queue_init(q); |