From: Janghyuck Kim Date: Wed, 20 Jun 2018 07:46:08 +0000 (+0900) Subject: media: videobuf2-core: add error handling for fence X-Git-Url: https://git.stricted.de/?a=commitdiff_plain;h=5978dd0bca5a71652c7991e2fb852a66c63a968f;p=GitHub%2FLineageOS%2Fandroid_kernel_motorola_exynos9610.git media: videobuf2-core: add error handling for fence Vb2-core supports in-fence and out-fence for buffer synchronization. However, in-fence might not be signaled by unexpected situation. Current logic is waiting for fence signaling infinitely. This patch added timer when in-fence without signaled is coming, and it will be expired if callback for in-fence would not be called, which means in-fence was not signaled during 1000 ms. This case is timeout and buffer is passed into driver by buf_queue callback, however, it would be marked with error status. To support this error handling, vb2-core logic is changed to use workqueue to avoid calling buf_queue callback in interrupt context. Change-Id: Icd533c355fa83605e958c8058a676256a6940f14 Signed-off-by: Janghyuck Kim --- diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index 50bbd25927ab..0ea4ab09d2a7 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c @@ -188,6 +188,7 @@ module_param(debug, int, 0644); static void __vb2_queue_cancel(struct vb2_queue *q); static void __enqueue_in_driver(struct vb2_buffer *vb); +static void __qbuf_work(struct work_struct *work); /** * __vb2_buf_mem_alloc() - allocate video memory for the given buffer @@ -351,6 +352,7 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory, vb->index = q->num_buffers + buffer; vb->type = q->type; vb->memory = memory; + INIT_WORK(&vb->qbuf_work, __qbuf_work); spin_lock_init(&vb->fence_cb_lock); for (plane = 0; plane < num_planes; ++plane) { vb->planes[plane].length = plane_sizes[plane]; @@ -1416,13 +1418,30 @@ static int vb2_start_streaming(struct vb2_queue *q) return ret; } +static void __qbuf_work(struct work_struct *work) +{ + struct vb2_buffer *vb; + struct vb2_queue *q; + unsigned long flags; + + vb = container_of(work, struct vb2_buffer, qbuf_work); + q = vb->vb2_queue; + + if (q->start_streaming_called) + __enqueue_in_driver(vb); +} + static void vb2_qbuf_fence_cb(struct dma_fence *f, struct dma_fence_cb *cb) { struct vb2_buffer *vb = container_of(cb, struct vb2_buffer, fence_cb); - struct vb2_queue *q = vb->vb2_queue; unsigned long flags; spin_lock_irqsave(&vb->fence_cb_lock, flags); + del_timer(&vb->fence_timer); + if (!vb->in_fence) { + spin_unlock_irqrestore(&vb->fence_cb_lock, flags); + return; + } /* * If the fence signals with an error we mark the buffer as such * and avoid using it by setting it to VB2_BUF_STATE_ERROR and @@ -1444,8 +1463,48 @@ static void vb2_qbuf_fence_cb(struct dma_fence *f, struct dma_fence_cb *cb) } spin_unlock_irqrestore(&vb->fence_cb_lock, flags); - if (q->start_streaming_called) - __enqueue_in_driver(vb); + schedule_work(&vb->qbuf_work); +} + +#define VB2_FENCE_TIMEOUT (1000) +static void vb2_fence_timeout_handler(unsigned long arg) +{ + struct vb2_buffer *vb = (struct vb2_buffer *)arg; + struct vb2_queue *q = vb->vb2_queue; + struct dma_fence *fence; + unsigned long flags; + char name[32]; + + pr_err("%s: fence callback is not called during %d ms\n", + __func__, VB2_FENCE_TIMEOUT); + spin_lock_irqsave(&vb->fence_cb_lock, flags); + if (!vb->in_fence) { + spin_unlock_irqrestore(&vb->fence_cb_lock, flags); + return; + } + + fence = vb->in_fence; + if (fence) { + strlcpy(name, fence->ops->get_driver_name(fence), + sizeof(name)); + pr_err("%s: vb2 in-fence: %s #%d (%s), error: %d\n", + __func__, name, fence->seqno, + dma_fence_is_signaled(fence) ? + "signaled" : "active", fence->error); + + dma_fence_remove_callback(vb->in_fence, &vb->fence_cb); + dma_fence_put(fence); + vb->in_fence = NULL; + vb->state = VB2_BUF_STATE_ERROR; + } + + fence = vb->out_fence; + if (fence) + pr_err("%s: vb2 out-fence: #%d\n", __func__, fence->seqno); + + spin_unlock_irqrestore(&vb->fence_cb_lock, flags); + + schedule_work(&vb->qbuf_work); } int vb2_core_qbuf(struct vb2_queue *q, unsigned int index, void *pb, @@ -1508,6 +1567,11 @@ int vb2_core_qbuf(struct vb2_queue *q, unsigned int index, void *pb, vb->in_fence = NULL; } else if (ret) { goto unlock; + } else { + setup_timer(&vb->fence_timer, + vb2_fence_timeout_handler, (unsigned long)vb); + mod_timer(&vb->fence_timer, + jiffies + msecs_to_jiffies(VB2_FENCE_TIMEOUT)); } } spin_unlock_irqrestore(&vb->fence_cb_lock, flags); diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h index 360c9abc2dd7..4ad5406a1d64 100644 --- a/include/media/videobuf2-core.h +++ b/include/media/videobuf2-core.h @@ -271,8 +271,11 @@ struct vb2_buffer { struct dma_fence *in_fence; struct dma_fence_cb fence_cb; + struct work_struct qbuf_work; spinlock_t fence_cb_lock; + struct timer_list fence_timer; + int out_fence_fd; struct dma_fence *out_fence; struct sync_file *sync_file;