diff options
author | Hans Verkuil <hans.verkuil@cisco.com> | 2012-11-16 10:03:06 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2012-11-22 09:36:29 -0500 |
commit | aec968326df3c60d140c4bcb00f2ee982acd01cb (patch) | |
tree | 9971347e493ee04c1451014eafc759da40ea6024 /drivers/media | |
parent | 94b76a88f16c869109c41380c77f4a2b847650e3 (diff) |
[media] vpif_capture: protect dma_queue by a spin_lock
The dma_queue list is accessed by both the interrupt handler and by normal
code. It needs to be protected by a lock to prevent possible list corruption.
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Acked-by: Lad, Prabhakar <prabhakar.lad@ti.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media')
-rw-r--r-- | drivers/media/platform/davinci/vpif_capture.c | 26 |
1 files changed, 23 insertions, 3 deletions
diff --git a/drivers/media/platform/davinci/vpif_capture.c b/drivers/media/platform/davinci/vpif_capture.c index 41890a938830..a409ccefb380 100644 --- a/drivers/media/platform/davinci/vpif_capture.c +++ b/drivers/media/platform/davinci/vpif_capture.c | |||
@@ -201,13 +201,16 @@ static void vpif_buffer_queue(struct vb2_buffer *vb) | |||
201 | struct vpif_cap_buffer *buf = container_of(vb, | 201 | struct vpif_cap_buffer *buf = container_of(vb, |
202 | struct vpif_cap_buffer, vb); | 202 | struct vpif_cap_buffer, vb); |
203 | struct common_obj *common; | 203 | struct common_obj *common; |
204 | unsigned long flags; | ||
204 | 205 | ||
205 | common = &ch->common[VPIF_VIDEO_INDEX]; | 206 | common = &ch->common[VPIF_VIDEO_INDEX]; |
206 | 207 | ||
207 | vpif_dbg(2, debug, "vpif_buffer_queue\n"); | 208 | vpif_dbg(2, debug, "vpif_buffer_queue\n"); |
208 | 209 | ||
210 | spin_lock_irqsave(&common->irqlock, flags); | ||
209 | /* add the buffer to the DMA queue */ | 211 | /* add the buffer to the DMA queue */ |
210 | list_add_tail(&buf->list, &common->dma_queue); | 212 | list_add_tail(&buf->list, &common->dma_queue); |
213 | spin_unlock_irqrestore(&common->irqlock, flags); | ||
211 | } | 214 | } |
212 | 215 | ||
213 | /** | 216 | /** |
@@ -278,10 +281,13 @@ static int vpif_start_streaming(struct vb2_queue *vq, unsigned int count) | |||
278 | struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; | 281 | struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; |
279 | struct vpif_params *vpif = &ch->vpifparams; | 282 | struct vpif_params *vpif = &ch->vpifparams; |
280 | unsigned long addr = 0; | 283 | unsigned long addr = 0; |
284 | unsigned long flags; | ||
281 | int ret; | 285 | int ret; |
282 | 286 | ||
283 | /* If buffer queue is empty, return error */ | 287 | /* If buffer queue is empty, return error */ |
288 | spin_lock_irqsave(&common->irqlock, flags); | ||
284 | if (list_empty(&common->dma_queue)) { | 289 | if (list_empty(&common->dma_queue)) { |
290 | spin_unlock_irqrestore(&common->irqlock, flags); | ||
285 | vpif_dbg(1, debug, "buffer queue is empty\n"); | 291 | vpif_dbg(1, debug, "buffer queue is empty\n"); |
286 | return -EIO; | 292 | return -EIO; |
287 | } | 293 | } |
@@ -291,6 +297,7 @@ static int vpif_start_streaming(struct vb2_queue *vq, unsigned int count) | |||
291 | struct vpif_cap_buffer, list); | 297 | struct vpif_cap_buffer, list); |
292 | /* Remove buffer from the buffer queue */ | 298 | /* Remove buffer from the buffer queue */ |
293 | list_del(&common->cur_frm->list); | 299 | list_del(&common->cur_frm->list); |
300 | spin_unlock_irqrestore(&common->irqlock, flags); | ||
294 | /* Mark state of the current frame to active */ | 301 | /* Mark state of the current frame to active */ |
295 | common->cur_frm->vb.state = VB2_BUF_STATE_ACTIVE; | 302 | common->cur_frm->vb.state = VB2_BUF_STATE_ACTIVE; |
296 | /* Initialize field_id and started member */ | 303 | /* Initialize field_id and started member */ |
@@ -362,6 +369,7 @@ static int vpif_stop_streaming(struct vb2_queue *vq) | |||
362 | struct vpif_fh *fh = vb2_get_drv_priv(vq); | 369 | struct vpif_fh *fh = vb2_get_drv_priv(vq); |
363 | struct channel_obj *ch = fh->channel; | 370 | struct channel_obj *ch = fh->channel; |
364 | struct common_obj *common; | 371 | struct common_obj *common; |
372 | unsigned long flags; | ||
365 | 373 | ||
366 | if (!vb2_is_streaming(vq)) | 374 | if (!vb2_is_streaming(vq)) |
367 | return 0; | 375 | return 0; |
@@ -369,12 +377,14 @@ static int vpif_stop_streaming(struct vb2_queue *vq) | |||
369 | common = &ch->common[VPIF_VIDEO_INDEX]; | 377 | common = &ch->common[VPIF_VIDEO_INDEX]; |
370 | 378 | ||
371 | /* release all active buffers */ | 379 | /* release all active buffers */ |
380 | spin_lock_irqsave(&common->irqlock, flags); | ||
372 | while (!list_empty(&common->dma_queue)) { | 381 | while (!list_empty(&common->dma_queue)) { |
373 | common->next_frm = list_entry(common->dma_queue.next, | 382 | common->next_frm = list_entry(common->dma_queue.next, |
374 | struct vpif_cap_buffer, list); | 383 | struct vpif_cap_buffer, list); |
375 | list_del(&common->next_frm->list); | 384 | list_del(&common->next_frm->list); |
376 | vb2_buffer_done(&common->next_frm->vb, VB2_BUF_STATE_ERROR); | 385 | vb2_buffer_done(&common->next_frm->vb, VB2_BUF_STATE_ERROR); |
377 | } | 386 | } |
387 | spin_unlock_irqrestore(&common->irqlock, flags); | ||
378 | 388 | ||
379 | return 0; | 389 | return 0; |
380 | } | 390 | } |
@@ -420,10 +430,12 @@ static void vpif_schedule_next_buffer(struct common_obj *common) | |||
420 | { | 430 | { |
421 | unsigned long addr = 0; | 431 | unsigned long addr = 0; |
422 | 432 | ||
433 | spin_lock(&common->irqlock); | ||
423 | common->next_frm = list_entry(common->dma_queue.next, | 434 | common->next_frm = list_entry(common->dma_queue.next, |
424 | struct vpif_cap_buffer, list); | 435 | struct vpif_cap_buffer, list); |
425 | /* Remove that buffer from the buffer queue */ | 436 | /* Remove that buffer from the buffer queue */ |
426 | list_del(&common->next_frm->list); | 437 | list_del(&common->next_frm->list); |
438 | spin_unlock(&common->irqlock); | ||
427 | common->next_frm->vb.state = VB2_BUF_STATE_ACTIVE; | 439 | common->next_frm->vb.state = VB2_BUF_STATE_ACTIVE; |
428 | addr = vb2_dma_contig_plane_dma_addr(&common->next_frm->vb, 0); | 440 | addr = vb2_dma_contig_plane_dma_addr(&common->next_frm->vb, 0); |
429 | 441 | ||
@@ -468,8 +480,12 @@ static irqreturn_t vpif_channel_isr(int irq, void *dev_id) | |||
468 | /* Check the field format */ | 480 | /* Check the field format */ |
469 | if (1 == ch->vpifparams.std_info.frm_fmt) { | 481 | if (1 == ch->vpifparams.std_info.frm_fmt) { |
470 | /* Progressive mode */ | 482 | /* Progressive mode */ |
471 | if (list_empty(&common->dma_queue)) | 483 | spin_lock(&common->irqlock); |
484 | if (list_empty(&common->dma_queue)) { | ||
485 | spin_unlock(&common->irqlock); | ||
472 | continue; | 486 | continue; |
487 | } | ||
488 | spin_unlock(&common->irqlock); | ||
473 | 489 | ||
474 | if (!channel_first_int[i][channel_id]) | 490 | if (!channel_first_int[i][channel_id]) |
475 | vpif_process_buffer_complete(common); | 491 | vpif_process_buffer_complete(common); |
@@ -513,9 +529,13 @@ static irqreturn_t vpif_channel_isr(int irq, void *dev_id) | |||
513 | vpif_process_buffer_complete(common); | 529 | vpif_process_buffer_complete(common); |
514 | } else if (1 == fid) { | 530 | } else if (1 == fid) { |
515 | /* odd field */ | 531 | /* odd field */ |
532 | spin_lock(&common->irqlock); | ||
516 | if (list_empty(&common->dma_queue) || | 533 | if (list_empty(&common->dma_queue) || |
517 | (common->cur_frm != common->next_frm)) | 534 | (common->cur_frm != common->next_frm)) { |
535 | spin_unlock(&common->irqlock); | ||
518 | continue; | 536 | continue; |
537 | } | ||
538 | spin_unlock(&common->irqlock); | ||
519 | 539 | ||
520 | vpif_schedule_next_buffer(common); | 540 | vpif_schedule_next_buffer(common); |
521 | } | 541 | } |