[PATCH drm 4/6] drm: add drm_gem_prime_page_flip() helper

Alex Goins agoins at nvidia.com
Thu Oct 22 13:00:57 PDT 2015


From: agoins <agoins at nvidia.com>

Adds drm_gem_prime_page_flip(), a helper implementation of
prime_page_flip() to be used by DRM drivers.

Signed-off-by: Alex Goins <agoins at nvidia.com>
---
 drivers/gpu/drm/drm_prime.c | 147 ++++++++++++++++++++++++++++++++++++++++++++
 include/drm/drmP.h          |   3 +
 2 files changed, 150 insertions(+)

diff --git a/drivers/gpu/drm/drm_prime.c b/drivers/gpu/drm/drm_prime.c
index 2956a65..175bf4a 100644
--- a/drivers/gpu/drm/drm_prime.c
+++ b/drivers/gpu/drm/drm_prime.c
@@ -61,6 +61,11 @@
  * use the drm_gem_prime_{import,export} helpers.
  */
 
+struct drm_prime_fence {
+	struct fence base;
+	spinlock_t lock;
+};
+
 struct drm_prime_fence_ctx {
 	uint32_t context;
 	uint32_t seqno;
@@ -78,6 +83,16 @@ struct drm_prime_attachment {
 	enum dma_data_direction dir;
 };
 
+struct drm_gem_prime_page_flip_cb {
+	struct fence_cb base;
+	struct drm_device *dev;
+	uint32_t crtc_id;
+	uint32_t fb_id;
+	uint32_t flags;
+	uint64_t user_data;
+	struct drm_file *file_priv;
+};
+
 static int drm_prime_add_buf_handle(struct drm_prime_file_private *prime_fpriv,
 				    struct dma_buf *dma_buf, uint32_t handle)
 {
@@ -316,6 +331,28 @@ static const struct dma_buf_ops drm_gem_prime_dmabuf_ops =  {
 	.vunmap = drm_gem_dmabuf_vunmap,
 };
 
+static const char *drm_gem_prime_get_driver_name(struct fence *fence)
+{
+	return "PRIME";
+}
+
+static const char *drm_gem_prime_get_timeline_name(struct fence *fence)
+{
+	return "prime.swonly";
+}
+
+static bool drm_gem_prime_enable_signaling(struct fence *fence)
+{
+	return true; /* SW signaling only */
+}
+
+static const struct fence_ops drm_gem_prime_fence_ops = {
+	.get_driver_name = drm_gem_prime_get_driver_name,
+	.get_timeline_name = drm_gem_prime_get_timeline_name,
+	.enable_signaling = drm_gem_prime_enable_signaling,
+	.wait = fence_default_wait,
+};
+
 /**
  * DOC: PRIME Helpers
  *
@@ -680,6 +717,116 @@ int drm_prime_fd_to_handle_ioctl(struct drm_device *dev, void *data,
 			args->fd, &args->handle);
 }
 
+/* Callback used by drm_gem_prime_page_flip(). Is added to a fence such that
+ * when the fence is signaled, page flip is requested with given parameters. */
+static void drm_gem_prime_page_flip_cb(struct fence *fence,
+				       struct fence_cb *cb)
+{
+	struct drm_gem_prime_page_flip_cb *page_flip_cb =
+		container_of(cb, struct drm_gem_prime_page_flip_cb, base);
+
+	drm_mode_page_flip(page_flip_cb->dev,
+			   page_flip_cb->crtc_id,
+			   page_flip_cb->fb_id,
+			   page_flip_cb->flags,
+			   page_flip_cb->user_data,
+			   page_flip_cb->file_priv);
+
+	kfree(cb);
+}
+
+/**
+ * drm_gem_prime_page_flip -
+ *     helper library implementation of the page flip callback
+ *
+ * @dev: DRM device
+ * @file_priv: DRM file info
+ * @handle: buffer handle to fence
+ * @fb_id: FB to update to
+ * @crtc_id: CRTC to update
+ * @user_data: Returned as user_data field in in the vblank event struct
+ * @flags: Flags modifying page flip behavior, same as drm_mode_page_flip.
+ *
+ * This is the implementation of the prime_page_flip function for GEM drivers
+ * using the PRIME helpers.
+ */
+int drm_gem_prime_page_flip(struct drm_device *dev,
+			    struct drm_file *file_priv, uint32_t handle,
+			    uint32_t fb_id, uint32_t crtc_id,
+			    uint64_t user_data, uint32_t flags)
+{
+	int ret;
+
+	struct dma_buf *dmabuf;
+	struct fence *oldfence;
+	struct drm_prime_fence *fence;
+	struct drm_gem_prime_page_flip_cb *page_flip_cb;
+	struct drm_prime_member *member;
+	struct drm_prime_fence_ctx *fctx;
+
+	mutex_lock(&file_priv->prime.lock);
+
+	member = drm_prime_lookup_member_by_handle(&file_priv->prime,
+						   handle);
+	if (!member) {
+		/* Buffer is not a member of PRIME */
+		ret = -EINVAL;
+		goto out;
+	}
+
+	dmabuf = member->dma_buf;
+	fctx = &member->fctx;
+
+	/* Clear out old fence callbacks */
+	oldfence = reservation_object_get_excl(dmabuf->resv);
+	if (oldfence)
+		fence_signal(oldfence);
+
+	/* Create and initialize new fence */
+	fence = kmalloc(sizeof(*fence), GFP_KERNEL);
+	if (!fence) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	spin_lock_init(&fence->lock);
+	fence_init(&fence->base, &drm_gem_prime_fence_ops, &fence->lock,
+		   fctx->context, fctx->seqno++);
+
+	/* Create and initialize new page flip callback */
+	page_flip_cb = kmalloc(sizeof(*page_flip_cb), GFP_KERNEL);
+	if (!page_flip_cb) {
+		ret = -ENOMEM;
+		fence_free(&fence->base);
+		goto out;
+	}
+
+	*page_flip_cb = (struct drm_gem_prime_page_flip_cb) {
+		.dev = dev,
+		.crtc_id = crtc_id,
+		.fb_id = fb_id,
+		.flags = flags,
+		.user_data = user_data,
+		.file_priv = file_priv,
+	};
+
+	ret = fence_add_callback(&fence->base, &page_flip_cb->base,
+				 drm_gem_prime_page_flip_cb);
+	if (ret) {
+		fence_free(&fence->base);
+		kfree(page_flip_cb);
+		goto out;
+	}
+
+	/* Add new fence */
+	reservation_object_add_excl_fence(dmabuf->resv, &fence->base);
+	fence_put(&fence->base); /* Reservation object has reference */
+out:
+	mutex_unlock(&file_priv->prime.lock);
+	return ret;
+}
+EXPORT_SYMBOL(drm_gem_prime_page_flip);
+
 /**
  * drm_prime_pages_to_sg - converts a page array into an sg list
  * @pages: pointer to the array of page pointers to convert
diff --git a/include/drm/drmP.h b/include/drm/drmP.h
index 4d3b842..015d19b 100644
--- a/include/drm/drmP.h
+++ b/include/drm/drmP.h
@@ -1028,6 +1028,9 @@ extern struct drm_gem_object *drm_gem_prime_import(struct drm_device *dev,
 		struct dma_buf *dma_buf);
 extern int drm_gem_prime_fd_to_handle(struct drm_device *dev,
 		struct drm_file *file_priv, int prime_fd, uint32_t *handle);
+extern int drm_gem_prime_page_flip(struct drm_device *dev,
+		struct drm_file *file_priv, uint32_t handle, uint32_t fb_id,
+		uint32_t crtc_id, uint64_t user_data, uint32_t flags);
 extern void drm_gem_dmabuf_release(struct dma_buf *dma_buf);
 
 extern int drm_prime_sg_to_page_addr_arrays(struct sg_table *sgt, struct page **pages,
-- 
1.9.1



More information about the dri-devel mailing list