From: agoins <agoins@xxxxxxxxxx> 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@xxxxxxxxxx> --- 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 _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/dri-devel