@@ -353,6 +353,7 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory,
vb->planes[plane].length = plane_sizes[plane];
vb->planes[plane].min_length = plane_sizes[plane];
}
+ vb->out_fence_fd = -1;
q->bufs[vb->index] = vb;
/* Allocate video buffer memory for the MMAP type */
@@ -933,10 +934,22 @@ void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state)
case VB2_BUF_STATE_QUEUED:
return;
case VB2_BUF_STATE_REQUEUEING:
+ /*
+ * Explicit synchronization requires ordered queues for now,
+ * so WARN_ON if we are requeuing on an ordered queue.
+ */
+ if (vb->out_fence)
+ WARN_ON_ONCE(q->ordered);
+
if (q->start_streaming_called)
__enqueue_in_driver(vb);
return;
default:
+ dma_fence_signal(vb->out_fence);
+ dma_fence_put(vb->out_fence);
+ vb->out_fence = NULL;
+ vb->out_fence_fd = -1;
+
/* Inform any processes that may be waiting for buffers */
wake_up(&q->done_wq);
break;
@@ -1224,10 +1237,20 @@ static int __prepare_dmabuf(struct vb2_buffer *vb, const void *pb)
static void __enqueue_in_driver(struct vb2_buffer *vb)
{
struct vb2_queue *q = vb->vb2_queue;
+ struct vb2_fence *fence;
if (vb->in_fence && !dma_fence_is_signaled(vb->in_fence))
return;
+ spin_lock(&q->out_fence_lock);
+ fence = list_first_entry(&q->out_fence_list, struct vb2_fence, entry);
+ if (fence) {
+ vb->out_fence = dma_fence_get(fence->out_fence);
+ list_del(&fence->entry);
+ kfree(fence);
+ }
+ spin_unlock(&q->out_fence_lock);
+
vb->state = VB2_BUF_STATE_ACTIVE;
atomic_inc(&q->owned_by_drv_count);
@@ -1323,25 +1346,36 @@ EXPORT_SYMBOL_GPL(vb2_core_prepare_buf);
int vb2_setup_out_fence(struct vb2_queue *q, unsigned int index)
{
struct vb2_buffer *vb = q->bufs[index];
+ struct vb2_fence *fence;
vb->out_fence_fd = get_unused_fd_flags(O_CLOEXEC);
if (vb->out_fence_fd < 0)
return vb->out_fence_fd;
- vb->out_fence = vb2_fence_alloc();
- if (!vb->out_fence)
- goto err;
+ fence = kzalloc(sizeof(*fence), GFP_KERNEL);
+ if (!fence)
+ goto err_fd;
- vb->sync_file = sync_file_create(vb->out_fence);
- if (!vb->sync_file) {
- dma_fence_put(vb->out_fence);
- vb->out_fence = NULL;
- goto err;
+ fence->out_fence = vb2_fence_alloc();
+ if (!fence->out_fence)
+ goto err_fence;
+
+ fence->sync_file = sync_file_create(fence->out_fence);
+ if (!fence->sync_file) {
+ dma_fence_put(fence->out_fence);
+ goto err_fence;
}
+ spin_lock(&q->out_fence_lock);
+ list_add_tail(&fence->entry, &q->out_fence_list);
+ spin_unlock(&q->out_fence_lock);
+
return 0;
-err:
+err_fence:
+ kfree(fence);
+
+err_fd:
put_unused_fd(vb->out_fence_fd);
vb->out_fence_fd = -1;
return -ENOMEM;
@@ -1425,6 +1459,7 @@ static void vb2_qbuf_fence_cb(struct dma_fence *f, struct dma_fence_cb *cb)
int vb2_core_qbuf(struct vb2_queue *q, unsigned int index, void *pb,
struct dma_fence *fence)
{
+ struct vb2_fence *vb2_fence;
struct vb2_buffer *vb;
int ret;
@@ -1506,6 +1541,16 @@ int vb2_core_qbuf(struct vb2_queue *q, unsigned int index, void *pb,
vb->in_fence = NULL;
}
+ if (vb->out_fence_fd >= 0) {
+ spin_lock(&q->out_fence_lock);
+ vb2_fence = list_last_entry(&q->out_fence_list,
+ struct vb2_fence, entry);
+ spin_unlock(&q->out_fence_lock);
+ fd_install(vb->out_fence_fd, vb2_fence->sync_file->file);
+
+ vb2_fence->sync_file = NULL;
+ }
+
fill:
if (q->start_streaming_called && !vb->in_fence)
__enqueue_in_driver(vb);
@@ -1523,6 +1568,17 @@ int vb2_core_qbuf(struct vb2_queue *q, unsigned int index, void *pb,
vb->in_fence = NULL;
}
+ if (vb->out_fence_fd >= 0) {
+ spin_lock(&q->out_fence_lock);
+ vb2_fence = list_last_entry(&q->out_fence_list,
+ struct vb2_fence, entry);
+ fput(vb2_fence->sync_file->file);
+ list_del(&vb2_fence->entry);
+ kfree(vb2_fence);
+ spin_unlock(&q->out_fence_lock);
+ put_unused_fd(vb->out_fence_fd);
+ }
+
return ret;
}
@@ -1736,6 +1792,7 @@ static void __vb2_queue_cancel(struct vb2_queue *q)
{
unsigned int i;
struct vb2_buffer *vb;
+ struct vb2_fence *fence, *tmp;
/*
* Tell driver to stop all transactions and release all queued
@@ -1766,6 +1823,13 @@ static void __vb2_queue_cancel(struct vb2_queue *q)
}
}
+ spin_lock(&q->out_fence_lock);
+ list_for_each_entry_safe(fence, tmp, &q->out_fence_list, entry) {
+ list_del(&fence->entry);
+ kfree(fence);
+ }
+ spin_unlock(&q->out_fence_lock);
+
q->streaming = 0;
q->start_streaming_called = 0;
q->queued_count = 0;
@@ -1780,6 +1844,7 @@ static void __vb2_queue_cancel(struct vb2_queue *q)
* has not already dequeued before initiating cancel.
*/
INIT_LIST_HEAD(&q->done_list);
+ INIT_LIST_HEAD(&q->out_fence_list);
atomic_set(&q->owned_by_drv_count, 0);
wake_up_all(&q->done_wq);
@@ -2101,6 +2166,8 @@ int vb2_core_queue_init(struct vb2_queue *q)
INIT_LIST_HEAD(&q->queued_list);
INIT_LIST_HEAD(&q->done_list);
spin_lock_init(&q->done_lock);
+ INIT_LIST_HEAD(&q->out_fence_list);
+ spin_lock_init(&q->out_fence_lock);
mutex_init(&q->mmap_lock);
init_waitqueue_head(&q->done_wq);
@@ -223,7 +223,9 @@ static void __fill_v4l2_buffer(struct vb2_buffer *vb, void *pb)
b->sequence = vbuf->sequence;
b->reserved = 0;
- b->fence_fd = -1;
+ b->fence_fd = vb->out_fence_fd;
+ if (vb->out_fence_fd)
+ b->flags |= V4L2_BUF_FLAG_OUT_FENCE;
if (vb->in_fence)
b->flags |= V4L2_BUF_FLAG_IN_FENCE;
else
@@ -604,6 +606,15 @@ int vb2_qbuf(struct vb2_queue *q, struct v4l2_buffer *b)
}
}
+ if (b->flags & V4L2_BUF_FLAG_OUT_FENCE) {
+ ret = vb2_setup_out_fence(q, b->index);
+ if (ret) {
+ dprintk(1, "failed to set up out-fence\n");
+ dma_fence_put(fence);
+ return ret;
+ }
+ }
+
return vb2_core_qbuf(q, b->index, b, fence);
}
EXPORT_SYMBOL_GPL(vb2_qbuf);
@@ -265,7 +265,6 @@ struct vb2_buffer {
struct dma_fence_cb fence_cb;
struct dma_fence *out_fence;
- struct sync_file *sync_file;
int out_fence_fd;
#ifdef CONFIG_VIDEO_ADV_DEBUG
/*
@@ -428,6 +427,17 @@ struct vb2_buf_ops {
void (*buffer_queued)(struct vb2_buffer *vb);
};
+/*
+ * struct vb2_fence - fence related data
+ *
+ * XXX
+ */
+struct vb2_fence {
+ struct dma_fence *out_fence;
+ struct sync_file *sync_file;
+ struct list_head entry;
+};
+
/**
* struct vb2_queue - a videobuf queue
*
@@ -495,6 +505,8 @@ struct vb2_buf_ops {
* @done_list: list of buffers ready to be dequeued to userspace
* @done_lock: lock to protect done_list list
* @done_wq: waitqueue for processes waiting for buffers ready to be dequeued
+ * @out_fence_list: list of out fences waiting to be assigned to a buffer
+ * @out_fence_lock: lock to protect out_fence_list
* @alloc_devs: memory type/allocator-specific per-plane device
* @streaming: current streaming state
* @start_streaming_called: @start_streaming was called successfully and we
@@ -554,6 +566,9 @@ struct vb2_queue {
spinlock_t done_lock;
wait_queue_head_t done_wq;
+ struct list_head out_fence_list;
+ spinlock_t out_fence_lock;
+
struct device *alloc_devs[VB2_MAX_PLANES];
unsigned int streaming:1;