aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndy Walls <awalls@radix.net>2008-12-12 13:50:27 -0500
committerMauro Carvalho Chehab <mchehab@redhat.com>2008-12-30 06:38:32 -0500
commitabb096de82f6f920a06ca935f76925261e66b556 (patch)
tree51f71ecb1d420083e54162b32733cf237b5b2393
parent765f6f612ef69ada79f7ec2627dcbc49276bf7b5 (diff)
V4L/DVB (9804): cx18: Avoid making firmware API calls with the queue lock held
cx18: Avoid making firmware API calls with the queue lock held. The source of MPEG strem corruption when not holding the queue lock was found to be that the MPEG buffer could be retrieved by the user app before it was sync'ed for the host cpu. Incoming buffers are now sync'ed before being put on q_full and releasing the queue lock. We can thus avoid the sometimes lengthy call to the firmware for CPU_DE_SET_MDL while holding the queue lock, so we can get better performance. 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-mailbox.c15
-rw-r--r--drivers/media/video/cx18/cx18-queue.c13
-rw-r--r--drivers/media/video/cx18/cx18-streams.c37
-rw-r--r--drivers/media/video/cx18/cx18-streams.h2
4 files changed, 30 insertions, 37 deletions
diff --git a/drivers/media/video/cx18/cx18-mailbox.c b/drivers/media/video/cx18/cx18-mailbox.c
index 9d8220539be8..ca8d5f4b731a 100644
--- a/drivers/media/video/cx18/cx18-mailbox.c
+++ b/drivers/media/video/cx18/cx18-mailbox.c
@@ -163,7 +163,7 @@ static void epu_dma_done(struct cx18 *cx, struct cx18_epu_work_order *order)
163 * it's filled in). 163 * it's filled in).
164 * 164 *
165 * cx18_queue_get buf() will detect the lost buffers 165 * cx18_queue_get buf() will detect the lost buffers
166 * and put them back in rotation eventually. 166 * and send them back to q_free for fw rotation eventually.
167 */ 167 */
168 if ((order->flags & CX18_F_EWO_MB_STALE_UPON_RECEIPT) && 168 if ((order->flags & CX18_F_EWO_MB_STALE_UPON_RECEIPT) &&
169 !(id >= s->mdl_offset && 169 !(id >= s->mdl_offset &&
@@ -174,24 +174,27 @@ static void epu_dma_done(struct cx18 *cx, struct cx18_epu_work_order *order)
174 break; 174 break;
175 } 175 }
176 buf = cx18_queue_get_buf(s, id, mdl_ack->data_used); 176 buf = cx18_queue_get_buf(s, id, mdl_ack->data_used);
177
177 CX18_DEBUG_HI_DMA("DMA DONE for %s (buffer %d)\n", s->name, id); 178 CX18_DEBUG_HI_DMA("DMA DONE for %s (buffer %d)\n", s->name, id);
178 if (buf == NULL) { 179 if (buf == NULL) {
179 CX18_WARN("Could not find buf %d for stream %s\n", 180 CX18_WARN("Could not find buf %d for stream %s\n",
180 id, s->name); 181 id, s->name);
182 /* Put as many buffers as possible back into fw use */
183 cx18_stream_load_fw_queue(s);
181 continue; 184 continue;
182 } 185 }
183 186
184 cx18_buf_sync_for_cpu(s, buf);
185 if (s->type == CX18_ENC_STREAM_TYPE_TS && s->dvb.enabled) { 187 if (s->type == CX18_ENC_STREAM_TYPE_TS && s->dvb.enabled) {
186 CX18_DEBUG_HI_DMA("TS recv bytesused = %d\n", 188 CX18_DEBUG_HI_DMA("TS recv bytesused = %d\n",
187 buf->bytesused); 189 buf->bytesused);
188
189 dvb_dmx_swfilter(&s->dvb.demux, buf->buf, 190 dvb_dmx_swfilter(&s->dvb.demux, buf->buf,
190 buf->bytesused); 191 buf->bytesused);
191 192 }
193 /* Put as many buffers as possible back into fw use */
194 cx18_stream_load_fw_queue(s);
195 /* Put back TS buffer, since it was removed from all queues */
196 if (s->type == CX18_ENC_STREAM_TYPE_TS)
192 cx18_stream_put_buf_fw(s, buf); 197 cx18_stream_put_buf_fw(s, buf);
193 } else
194 set_bit(CX18_F_B_NEED_BUF_SWAP, &buf->b_flags);
195 } 198 }
196 wake_up(&cx->dma_waitq); 199 wake_up(&cx->dma_waitq);
197 if (s->id != -1) 200 if (s->id != -1)
diff --git a/drivers/media/video/cx18/cx18-queue.c b/drivers/media/video/cx18/cx18-queue.c
index 40379d807cef..a6b0666f0ba3 100644
--- a/drivers/media/video/cx18/cx18-queue.c
+++ b/drivers/media/video/cx18/cx18-queue.c
@@ -117,16 +117,18 @@ struct cx18_buffer *cx18_queue_get_buf(struct cx18_stream *s, u32 id,
117 } 117 }
118 118
119 buf->bytesused = bytesused; 119 buf->bytesused = bytesused;
120 /* Sync the buffer before we release the qlock */
121 cx18_buf_sync_for_cpu(s, buf);
120 if (s->type == CX18_ENC_STREAM_TYPE_TS) { 122 if (s->type == CX18_ENC_STREAM_TYPE_TS) {
121 /* 123 /*
122 * TS doesn't use q_full, but for sweeping up lost 124 * TS doesn't use q_full. As we pull the buffer off of
123 * buffers, we want the TS to requeue the buffer just 125 * the queue here, the caller will have to put it back.
124 * before sending the MDL back to the firmware, so we
125 * pull it off the list here.
126 */ 126 */
127 list_del_init(&buf->list); 127 list_del_init(&buf->list);
128 } else { 128 } else {
129 /* Move buffer from q_busy to q_full */
129 list_move_tail(&buf->list, &s->q_full.list); 130 list_move_tail(&buf->list, &s->q_full.list);
131 set_bit(CX18_F_B_NEED_BUF_SWAP, &buf->b_flags);
130 s->q_full.bytesused += buf->bytesused; 132 s->q_full.bytesused += buf->bytesused;
131 atomic_inc(&s->q_full.buffers); 133 atomic_inc(&s->q_full.buffers);
132 } 134 }
@@ -135,9 +137,6 @@ struct cx18_buffer *cx18_queue_get_buf(struct cx18_stream *s, u32 id,
135 ret = buf; 137 ret = buf;
136 break; 138 break;
137 } 139 }
138
139 /* Put more buffers into the transfer rotation from q_free, if we can */
140 cx18_stream_load_fw_queue_nolock(s);
141 mutex_unlock(&s->qlock); 140 mutex_unlock(&s->qlock);
142 return ret; 141 return ret;
143} 142}
diff --git a/drivers/media/video/cx18/cx18-streams.c b/drivers/media/video/cx18/cx18-streams.c
index d2690ccdf327..9ead4591b1d2 100644
--- a/drivers/media/video/cx18/cx18-streams.c
+++ b/drivers/media/video/cx18/cx18-streams.c
@@ -419,31 +419,22 @@ struct cx18_queue *cx18_stream_put_buf_fw(struct cx18_stream *s,
419 return q; 419 return q;
420} 420}
421 421
422/* Must hold s->qlock when calling */ 422void cx18_stream_load_fw_queue(struct cx18_stream *s)
423void cx18_stream_load_fw_queue_nolock(struct cx18_stream *s)
424{ 423{
424 struct cx18_queue *q;
425 struct cx18_buffer *buf; 425 struct cx18_buffer *buf;
426 struct cx18 *cx = s->cx;
427 426
428 /* Move from q_free to q_busy notifying the firmware: 63 buf limit */ 427 if (atomic_read(&s->q_free.buffers) == 0 ||
429 while (s->handle != CX18_INVALID_TASK_HANDLE && 428 atomic_read(&s->q_busy.buffers) >= 63)
430 test_bit(CX18_F_S_STREAMING, &s->s_flags) && 429 return;
431 atomic_read(&s->q_busy.buffers) < 63 && 430
432 !list_empty(&s->q_free.list)) { 431 /* Move from q_free to q_busy notifying the firmware, until the limit */
433 432 do {
434 /* Move from q_free to q_busy */ 433 buf = cx18_dequeue(s, &s->q_free);
435 buf = list_entry(s->q_free.list.next, struct cx18_buffer, list); 434 if (buf == NULL)
436 list_move_tail(&buf->list, &s->q_busy.list); 435 break;
437 buf->bytesused = buf->readpos = buf->b_flags = buf->skipped = 0; 436 q = cx18_stream_put_buf_fw(s, buf);
438 atomic_dec(&s->q_free.buffers); 437 } while (atomic_read(&s->q_busy.buffers) < 63 && q == &s->q_busy);
439 atomic_inc(&s->q_busy.buffers);
440
441 /* Notify firmware */
442 cx18_buf_sync_for_device(s, buf);
443 cx18_vapi(cx, CX18_CPU_DE_SET_MDL, 5, s->handle,
444 (void __iomem *) &cx->scb->cpu_mdl[buf->id] - cx->enc_mem,
445 1, buf->id, s->buf_size);
446 }
447} 438}
448 439
449int cx18_start_v4l2_encode_stream(struct cx18_stream *s) 440int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
@@ -543,8 +534,8 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
543 &cx->scb->cpu_mdl[buf->id].paddr); 534 &cx->scb->cpu_mdl[buf->id].paddr);
544 cx18_writel(cx, s->buf_size, &cx->scb->cpu_mdl[buf->id].length); 535 cx18_writel(cx, s->buf_size, &cx->scb->cpu_mdl[buf->id].length);
545 } 536 }
546 cx18_stream_load_fw_queue_nolock(s);
547 mutex_unlock(&s->qlock); 537 mutex_unlock(&s->qlock);
538 cx18_stream_load_fw_queue(s);
548 539
549 /* begin_capture */ 540 /* begin_capture */
550 if (cx18_vapi(cx, CX18_CPU_CAPTURE_START, 1, s->handle)) { 541 if (cx18_vapi(cx, CX18_CPU_CAPTURE_START, 1, s->handle)) {
diff --git a/drivers/media/video/cx18/cx18-streams.h b/drivers/media/video/cx18/cx18-streams.h
index 635d34b75ab1..420e0a172945 100644
--- a/drivers/media/video/cx18/cx18-streams.h
+++ b/drivers/media/video/cx18/cx18-streams.h
@@ -29,7 +29,7 @@ int cx18_streams_register(struct cx18 *cx);
29void cx18_streams_cleanup(struct cx18 *cx, int unregister); 29void cx18_streams_cleanup(struct cx18 *cx, int unregister);
30 30
31/* Capture related */ 31/* Capture related */
32void cx18_stream_load_fw_queue_nolock(struct cx18_stream *s); 32void cx18_stream_load_fw_queue(struct cx18_stream *s);
33struct cx18_queue *cx18_stream_put_buf_fw(struct cx18_stream *s, 33struct cx18_queue *cx18_stream_put_buf_fw(struct cx18_stream *s,
34 struct cx18_buffer *buf); 34 struct cx18_buffer *buf);
35int cx18_start_v4l2_encode_stream(struct cx18_stream *s); 35int cx18_start_v4l2_encode_stream(struct cx18_stream *s);