Commit c4697d7f authored by Hans Verkuil's avatar Hans Verkuil Committed by Mauro Carvalho Chehab

[media] vpif_display: 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.
Corruption has been observed in 'real-life' conditions. Adding this lock made
it go away.
Signed-off-by: default avatarHans Verkuil <hans.verkuil@cisco.com>
Acked-by: default avatarLad, Prabhakar <prabhakar.lad@ti.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent aec96832
...@@ -177,11 +177,14 @@ static void vpif_buffer_queue(struct vb2_buffer *vb) ...@@ -177,11 +177,14 @@ static void vpif_buffer_queue(struct vb2_buffer *vb)
struct vpif_disp_buffer, vb); struct vpif_disp_buffer, vb);
struct channel_obj *ch = fh->channel; struct channel_obj *ch = fh->channel;
struct common_obj *common; struct common_obj *common;
unsigned long flags;
common = &ch->common[VPIF_VIDEO_INDEX]; common = &ch->common[VPIF_VIDEO_INDEX];
/* add the buffer to the DMA queue */ /* add the buffer to the DMA queue */
spin_lock_irqsave(&common->irqlock, flags);
list_add_tail(&buf->list, &common->dma_queue); list_add_tail(&buf->list, &common->dma_queue);
spin_unlock_irqrestore(&common->irqlock, flags);
} }
/* /*
...@@ -246,10 +249,13 @@ static int vpif_start_streaming(struct vb2_queue *vq, unsigned int count) ...@@ -246,10 +249,13 @@ static int vpif_start_streaming(struct vb2_queue *vq, unsigned int count)
struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
struct vpif_params *vpif = &ch->vpifparams; struct vpif_params *vpif = &ch->vpifparams;
unsigned long addr = 0; unsigned long addr = 0;
unsigned long flags;
int ret; int ret;
/* If buffer queue is empty, return error */ /* If buffer queue is empty, return error */
spin_lock_irqsave(&common->irqlock, flags);
if (list_empty(&common->dma_queue)) { if (list_empty(&common->dma_queue)) {
spin_unlock_irqrestore(&common->irqlock, flags);
vpif_err("buffer queue is empty\n"); vpif_err("buffer queue is empty\n");
return -EIO; return -EIO;
} }
...@@ -260,6 +266,7 @@ static int vpif_start_streaming(struct vb2_queue *vq, unsigned int count) ...@@ -260,6 +266,7 @@ static int vpif_start_streaming(struct vb2_queue *vq, unsigned int count)
struct vpif_disp_buffer, list); struct vpif_disp_buffer, list);
list_del(&common->cur_frm->list); list_del(&common->cur_frm->list);
spin_unlock_irqrestore(&common->irqlock, flags);
/* Mark state of the current frame to active */ /* Mark state of the current frame to active */
common->cur_frm->vb.state = VB2_BUF_STATE_ACTIVE; common->cur_frm->vb.state = VB2_BUF_STATE_ACTIVE;
...@@ -330,6 +337,7 @@ static int vpif_stop_streaming(struct vb2_queue *vq) ...@@ -330,6 +337,7 @@ static int vpif_stop_streaming(struct vb2_queue *vq)
struct vpif_fh *fh = vb2_get_drv_priv(vq); struct vpif_fh *fh = vb2_get_drv_priv(vq);
struct channel_obj *ch = fh->channel; struct channel_obj *ch = fh->channel;
struct common_obj *common; struct common_obj *common;
unsigned long flags;
if (!vb2_is_streaming(vq)) if (!vb2_is_streaming(vq))
return 0; return 0;
...@@ -337,12 +345,14 @@ static int vpif_stop_streaming(struct vb2_queue *vq) ...@@ -337,12 +345,14 @@ static int vpif_stop_streaming(struct vb2_queue *vq)
common = &ch->common[VPIF_VIDEO_INDEX]; common = &ch->common[VPIF_VIDEO_INDEX];
/* release all active buffers */ /* release all active buffers */
spin_lock_irqsave(&common->irqlock, flags);
while (!list_empty(&common->dma_queue)) { while (!list_empty(&common->dma_queue)) {
common->next_frm = list_entry(common->dma_queue.next, common->next_frm = list_entry(common->dma_queue.next,
struct vpif_disp_buffer, list); struct vpif_disp_buffer, list);
list_del(&common->next_frm->list); list_del(&common->next_frm->list);
vb2_buffer_done(&common->next_frm->vb, VB2_BUF_STATE_ERROR); vb2_buffer_done(&common->next_frm->vb, VB2_BUF_STATE_ERROR);
} }
spin_unlock_irqrestore(&common->irqlock, flags);
return 0; return 0;
} }
...@@ -363,11 +373,13 @@ static void process_progressive_mode(struct common_obj *common) ...@@ -363,11 +373,13 @@ static void process_progressive_mode(struct common_obj *common)
{ {
unsigned long addr = 0; unsigned long addr = 0;
spin_lock(&common->irqlock);
/* Get the next buffer from buffer queue */ /* Get the next buffer from buffer queue */
common->next_frm = list_entry(common->dma_queue.next, common->next_frm = list_entry(common->dma_queue.next,
struct vpif_disp_buffer, list); struct vpif_disp_buffer, list);
/* Remove that buffer from the buffer queue */ /* Remove that buffer from the buffer queue */
list_del(&common->next_frm->list); list_del(&common->next_frm->list);
spin_unlock(&common->irqlock);
/* Mark status of the buffer as active */ /* Mark status of the buffer as active */
common->next_frm->vb.state = VB2_BUF_STATE_ACTIVE; common->next_frm->vb.state = VB2_BUF_STATE_ACTIVE;
...@@ -398,16 +410,18 @@ static void process_interlaced_mode(int fid, struct common_obj *common) ...@@ -398,16 +410,18 @@ static void process_interlaced_mode(int fid, struct common_obj *common)
common->cur_frm = common->next_frm; common->cur_frm = common->next_frm;
} else if (1 == fid) { /* odd field */ } else if (1 == fid) { /* odd field */
spin_lock(&common->irqlock);
if (list_empty(&common->dma_queue) if (list_empty(&common->dma_queue)
|| (common->cur_frm != common->next_frm)) { || (common->cur_frm != common->next_frm)) {
spin_unlock(&common->irqlock);
return; return;
} }
spin_unlock(&common->irqlock);
/* one field is displayed configure the next /* one field is displayed configure the next
* frame if it is available else hold on current * frame if it is available else hold on current
* frame */ * frame */
/* Get next from the buffer queue */ /* Get next from the buffer queue */
process_progressive_mode(common); process_progressive_mode(common);
} }
} }
...@@ -437,8 +451,12 @@ static irqreturn_t vpif_channel_isr(int irq, void *dev_id) ...@@ -437,8 +451,12 @@ static irqreturn_t vpif_channel_isr(int irq, void *dev_id)
continue; continue;
if (1 == ch->vpifparams.std_info.frm_fmt) { if (1 == ch->vpifparams.std_info.frm_fmt) {
if (list_empty(&common->dma_queue)) spin_lock(&common->irqlock);
if (list_empty(&common->dma_queue)) {
spin_unlock(&common->irqlock);
continue; continue;
}
spin_unlock(&common->irqlock);
/* Progressive mode */ /* Progressive mode */
if (!channel_first_int[i][channel_id]) { if (!channel_first_int[i][channel_id]) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment