aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNikhil Devshatwar2014-04-28 09:21:14 -0500
committerRakesh Movva2014-05-01 14:30:21 -0500
commitad429e8ade4bd66323f02e16ac6db79aa45a06ba (patch)
treeb6d7a8aa1490092869c7d5067f929e15b813e861
parent4faa75be0042faa66c54600d3c13b2c164303747 (diff)
downloadkernel-video-vip.tar.gz
kernel-video-vip.tar.xz
kernel-video-vip.zip
v4l: ti-vps: vip: Different list_head for dequeue listvip
VIP driver maintains two lists stream->vidq = List of buffers which are queued by user space (queue) dev->vip_bufs = List of buffers waiting for DMA completion (dequeue) At any point of time, a buffer would be present in only one of them. But when buffers are dropped continously, and suddenly user space starts queueing the buffers, some buffers need to be held by the dequeue list even if they are already dequeued. This scenario causes list corruption and eventually kernel crash. Solution to this problem would be to use a different list for maintaining buffers which are waiting for DMA. This would allow referencing the buffer from both lists. Change-Id: I5a615f32a183eecc33e01a3f71b2a4885be9b047 Signed-off-by: Nikhil Devshatwar <nikhil.nd@ti.com>
-rw-r--r--drivers/media/platform/ti-vps/vip.c18
-rw-r--r--drivers/media/platform/ti-vps/vip.h1
2 files changed, 12 insertions, 7 deletions
diff --git a/drivers/media/platform/ti-vps/vip.c b/drivers/media/platform/ti-vps/vip.c
index 7bb7513e4f5..38982275f05 100644
--- a/drivers/media/platform/ti-vps/vip.c
+++ b/drivers/media/platform/ti-vps/vip.c
@@ -932,7 +932,8 @@ static void vip_active_buf_next(struct vip_stream *stream)
932 if (list_empty(&stream->vidq)) { 932 if (list_empty(&stream->vidq)) {
933 vip_dprintk(dev, "Dropping frame"); 933 vip_dprintk(dev, "Dropping frame");
934 /* Increment drop_count for last buffer in the list */ 934 /* Increment drop_count for last buffer in the list */
935 buf = list_entry(dev->vip_bufs.prev, struct vip_buffer, list); 935 buf = list_entry(dev->vip_bufs.prev,
936 struct vip_buffer, dq_list);
936 buf->drop_count++; 937 buf->drop_count++;
937 buf = NULL; 938 buf = NULL;
938 939
@@ -940,7 +941,8 @@ static void vip_active_buf_next(struct vip_stream *stream)
940 buf = list_entry(stream->vidq.next, struct vip_buffer, list); 941 buf = list_entry(stream->vidq.next, struct vip_buffer, list);
941 buf->drop_count = 0; 942 buf->drop_count = 0;
942 buf->allow_dq = true; 943 buf->allow_dq = true;
943 list_move_tail(&buf->list, &dev->vip_bufs); 944 list_del(&buf->list);
945 list_add_tail(&buf->dq_list, &dev->vip_bufs);
944 } else { 946 } else {
945 v4l2_err(&dev->v4l2_dev, "IRQ occurred when not streaming"); 947 v4l2_err(&dev->v4l2_dev, "IRQ occurred when not streaming");
946 spin_unlock_irqrestore(&dev->slock, flags); 948 spin_unlock_irqrestore(&dev->slock, flags);
@@ -958,7 +960,7 @@ static void vip_process_buffer_complete(struct vip_stream *stream)
958 struct vip_buffer *buf; 960 struct vip_buffer *buf;
959 unsigned long flags, fld; 961 unsigned long flags, fld;
960 962
961 buf = list_first_entry(&dev->vip_bufs, struct vip_buffer, list); 963 buf = list_first_entry(&dev->vip_bufs, struct vip_buffer, dq_list);
962 964
963 if (stream->port->flags & FLAG_INTERLACED) { 965 if (stream->port->flags & FLAG_INTERLACED) {
964 vpdma_buf_unmap(dev->shared->vpdma, &dev->desc_list.buf); 966 vpdma_buf_unmap(dev->shared->vpdma, &dev->desc_list.buf);
@@ -977,7 +979,7 @@ static void vip_process_buffer_complete(struct vip_stream *stream)
977 979
978 if (buf->drop_count-- == 0) { 980 if (buf->drop_count-- == 0) {
979 spin_lock_irqsave(&dev->slock, flags); 981 spin_lock_irqsave(&dev->slock, flags);
980 list_del(&buf->list); 982 list_del(&buf->dq_list);
981 spin_unlock_irqrestore(&dev->slock, flags); 983 spin_unlock_irqrestore(&dev->slock, flags);
982 } 984 }
983 985
@@ -1537,7 +1539,8 @@ static int vip_start_streaming(struct vb2_queue *vq, unsigned int count)
1537 return -EBUSY; 1539 return -EBUSY;
1538 } 1540 }
1539 1541
1540 list_move_tail(&buf->list, &dev->vip_bufs); 1542 list_del(&buf->list);
1543 list_add_tail(&buf->dq_list, &dev->vip_bufs);
1541 spin_unlock_irqrestore(&dev->slock, flags); 1544 spin_unlock_irqrestore(&dev->slock, flags);
1542 1545
1543 start_dma(dev, buf); 1546 start_dma(dev, buf);
@@ -1564,8 +1567,9 @@ static int vip_stop_streaming(struct vb2_queue *vq)
1564 disable_irqs(dev, dev->slice_id); 1567 disable_irqs(dev, dev->slice_id);
1565 /* release all active buffers */ 1568 /* release all active buffers */
1566 while (!list_empty(&dev->vip_bufs)) { 1569 while (!list_empty(&dev->vip_bufs)) {
1567 buf = list_entry(dev->vip_bufs.next, struct vip_buffer, list); 1570 buf = list_entry(dev->vip_bufs.next,
1568 list_del(&buf->list); 1571 struct vip_buffer, dq_list);
1572 list_del(&buf->dq_list);
1569 vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); 1573 vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
1570 } 1574 }
1571 while (!list_empty(&stream->vidq)) { 1575 while (!list_empty(&stream->vidq)) {
diff --git a/drivers/media/platform/ti-vps/vip.h b/drivers/media/platform/ti-vps/vip.h
index 8cf04ef770d..1b41164f788 100644
--- a/drivers/media/platform/ti-vps/vip.h
+++ b/drivers/media/platform/ti-vps/vip.h
@@ -38,6 +38,7 @@ struct vip_buffer {
38 /* common v4l buffer stuff */ 38 /* common v4l buffer stuff */
39 struct vb2_buffer vb; 39 struct vb2_buffer vb;
40 struct list_head list; 40 struct list_head list;
41 struct list_head dq_list;
41 /* Number of buffers to drop after this */ 42 /* Number of buffers to drop after this */
42 int drop_count; 43 int drop_count;
43 /* To make sure same buffer isn't dequeued again */ 44 /* To make sure same buffer isn't dequeued again */