aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/cx18/cx18-mailbox.c
diff options
context:
space:
mode:
authorAndy Walls <awalls@radix.net>2008-11-18 23:24:33 -0500
committerMauro Carvalho Chehab <mchehab@redhat.com>2008-12-30 06:38:10 -0500
commitbca11a5721917d6d5874571813673a2669ffec4b (patch)
treea2202bdf236804a123175b12585f4aae4fdc58d7 /drivers/media/video/cx18/cx18-mailbox.c
parentd6c7e5f8faad080e75bace5c4f2265e3513e3510 (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-mailbox.c')
-rw-r--r--drivers/media/video/cx18/cx18-mailbox.c59
1 files changed, 46 insertions, 13 deletions
diff --git a/drivers/media/video/cx18/cx18-mailbox.c b/drivers/media/video/cx18/cx18-mailbox.c
index e5d4f3112293..abd39aaa345c 100644
--- a/drivers/media/video/cx18/cx18-mailbox.c
+++ b/drivers/media/video/cx18/cx18-mailbox.c
@@ -120,7 +120,7 @@ static void dump_mb(struct cx18 *cx, struct cx18_mailbox *mb, char *name)
120 120
121static void epu_dma_done(struct cx18 *cx, struct cx18_epu_work_order *order) 121static void epu_dma_done(struct cx18 *cx, struct cx18_epu_work_order *order)
122{ 122{
123 u32 handle, mdl_ack_count; 123 u32 handle, mdl_ack_count, id;
124 struct cx18_mailbox *mb; 124 struct cx18_mailbox *mb;
125 struct cx18_mdl_ack *mdl_ack; 125 struct cx18_mdl_ack *mdl_ack;
126 struct cx18_stream *s; 126 struct cx18_stream *s;
@@ -133,19 +133,50 @@ static void epu_dma_done(struct cx18 *cx, struct cx18_epu_work_order *order)
133 133
134 if (s == NULL) { 134 if (s == NULL) {
135 CX18_WARN("Got DMA done notification for unknown/inactive" 135 CX18_WARN("Got DMA done notification for unknown/inactive"
136 " handle %d\n", handle); 136 " handle %d, %s mailbox seq no %d\n", handle,
137 (order->flags & CX18_F_EWO_MB_STALE_UPON_RECEIPT) ?
138 "stale" : "good", mb->request);
137 return; 139 return;
138 } 140 }
139 141
140 mdl_ack_count = mb->args[2]; 142 mdl_ack_count = mb->args[2];
141 mdl_ack = order->mdl_ack; 143 mdl_ack = order->mdl_ack;
142 for (i = 0; i < mdl_ack_count; i++, mdl_ack++) { 144 for (i = 0; i < mdl_ack_count; i++, mdl_ack++) {
143 buf = cx18_queue_get_buf(s, mdl_ack->id, mdl_ack->data_used); 145 id = mdl_ack->id;
144 CX18_DEBUG_HI_DMA("DMA DONE for %s (buffer %d)\n", s->name, 146 /*
145 mdl_ack->id); 147 * Simple integrity check for processing a stale (and possibly
148 * inconsistent mailbox): make sure the buffer id is in the
149 * valid range for the stream.
150 *
151 * We go through the trouble of dealing with stale mailboxes
152 * because most of the time, the mailbox data is still valid and
153 * unchanged (and in practice the firmware ping-pongs the
154 * two mdl_ack buffers so mdl_acks are not stale).
155 *
156 * There are occasions when we get a half changed mailbox,
157 * which this check catches for a handle & id mismatch. If the
158 * handle and id do correspond, the worst case is that we
159 * completely lost the old buffer, but pick up the new buffer
160 * early (but the new mdl_ack is guaranteed to be good in this
161 * case as the firmware wouldn't point us to a new mdl_ack until
162 * it's filled in).
163 *
164 * cx18_queue_get buf() will detect the lost buffers
165 * and put them back in rotation eventually.
166 */
167 if ((order->flags & CX18_F_EWO_MB_STALE_UPON_RECEIPT) &&
168 !(id >= s->mdl_offset &&
169 id < (s->mdl_offset + s->buffers))) {
170 CX18_WARN("Fell behind! Ignoring stale mailbox with "
171 " inconsistent data. Lost buffer for mailbox "
172 "seq no %d\n", mb->request);
173 break;
174 }
175 buf = cx18_queue_get_buf(s, id, mdl_ack->data_used);
176 CX18_DEBUG_HI_DMA("DMA DONE for %s (buffer %d)\n", s->name, id);
146 if (buf == NULL) { 177 if (buf == NULL) {
147 CX18_WARN("Could not find buf %d for stream %s\n", 178 CX18_WARN("Could not find buf %d for stream %s\n",
148 mdl_ack->id, s->name); 179 id, s->name);
149 continue; 180 continue;
150 } 181 }
151 182
@@ -158,6 +189,7 @@ static void epu_dma_done(struct cx18 *cx, struct cx18_epu_work_order *order)
158 buf->bytesused); 189 buf->bytesused);
159 190
160 cx18_buf_sync_for_device(s, buf); 191 cx18_buf_sync_for_device(s, buf);
192 cx18_enqueue(s, buf, &s->q_free);
161 193
162 if (s->handle != CX18_INVALID_TASK_HANDLE && 194 if (s->handle != CX18_INVALID_TASK_HANDLE &&
163 test_bit(CX18_F_S_STREAMING, &s->s_flags)) 195 test_bit(CX18_F_S_STREAMING, &s->s_flags))
@@ -257,10 +289,10 @@ static void mb_ack_irq(struct cx18 *cx, struct cx18_epu_work_order *order)
257 /* Don't ack if the RPU has gotten impatient and timed us out */ 289 /* Don't ack if the RPU has gotten impatient and timed us out */
258 if (req != cx18_readl(cx, &ack_mb->request) || 290 if (req != cx18_readl(cx, &ack_mb->request) ||
259 req == cx18_readl(cx, &ack_mb->ack)) { 291 req == cx18_readl(cx, &ack_mb->ack)) {
260 CX18_WARN("Possibly falling behind: %s self-ack'ed our incoming" 292 CX18_DEBUG_WARN("Possibly falling behind: %s self-ack'ed our "
261 " %s to EPU mailbox (sequence no. %u) while " 293 "incoming %s to EPU mailbox (sequence no. %u) "
262 "processing\n", 294 "while processing\n",
263 rpu_str[order->rpu], rpu_str[order->rpu], req); 295 rpu_str[order->rpu], rpu_str[order->rpu], req);
264 order->flags |= CX18_F_EWO_MB_STALE_WHILE_PROC; 296 order->flags |= CX18_F_EWO_MB_STALE_WHILE_PROC;
265 return; 297 return;
266 } 298 }
@@ -407,9 +439,10 @@ void cx18_api_epu_cmd_irq(struct cx18 *cx, int rpu)
407 2 * sizeof(u32)); 439 2 * sizeof(u32));
408 440
409 if (order_mb->request == order_mb->ack) { 441 if (order_mb->request == order_mb->ack) {
410 CX18_WARN("Possibly falling behind: %s self-ack'ed our incoming" 442 CX18_DEBUG_WARN("Possibly falling behind: %s self-ack'ed our "
411 " %s to EPU mailbox (sequence no. %u)\n", 443 "incoming %s to EPU mailbox (sequence no. %u)"
412 rpu_str[rpu], rpu_str[rpu], order_mb->request); 444 "\n",
445 rpu_str[rpu], rpu_str[rpu], order_mb->request);
413 dump_mb(cx, order_mb, "incoming"); 446 dump_mb(cx, order_mb, "incoming");
414 order->flags = CX18_F_EWO_MB_STALE_UPON_RECEIPT; 447 order->flags = CX18_F_EWO_MB_STALE_UPON_RECEIPT;
415 } 448 }