From 38419124812673b4d0494d183df4c9479c8eedcb Mon Sep 17 00:00:00 2001 From: Mark Yao Date: Mon, 20 Mar 2017 09:46:47 +0800 Subject: [PATCH] dma-buf: add release callback support This patch is required by system on RK3368 SoCs. Since its system used ion and drm drivers together, one dma-buf may used by two devices, if one device deattached buffer, then the other one need to map sg again, that takes time several ms. The patch fix it by set buffer release operation in a list, and do release after final dma_buf_put. Change-Id: Ibfb4ffe3d97fae0a27f20032fdfbc3cc561aa375 Signed-off-by: Mark Yao Signed-off-by: Jianqun Xu --- drivers/dma-buf/dma-buf.c | 68 ++++++++++++++++++++++++++++++++++++++- include/linux/dma-buf.h | 19 ++++++++++- 2 files changed, 85 insertions(+), 2 deletions(-) diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c index f83bd522b2b9..235bdc85e101 100644 --- a/drivers/dma-buf/dma-buf.c +++ b/drivers/dma-buf/dma-buf.c @@ -41,6 +41,14 @@ static inline int is_dma_buf_file(struct file *); +#ifdef CONFIG_ARCH_ROCKCHIP +struct dma_buf_callback { + struct list_head list; + void (*callback)(void *); + void *data; +}; +#endif + struct dma_buf_list { struct list_head head; struct mutex lock; @@ -86,6 +94,9 @@ static struct file_system_type dma_buf_fs_type = { static int dma_buf_release(struct inode *inode, struct file *file) { struct dma_buf *dmabuf; +#ifdef CONFIG_ARCH_ROCKCHIP + struct dma_buf_callback *cb, *tmp; +#endif if (!is_dma_buf_file(file)) return -EINVAL; @@ -104,6 +115,17 @@ static int dma_buf_release(struct inode *inode, struct file *file) */ BUG_ON(dmabuf->cb_shared.active || dmabuf->cb_excl.active); +#ifdef CONFIG_ARCH_ROCKCHIP + mutex_lock(&dmabuf->release_lock); + list_for_each_entry_safe(cb, tmp, &dmabuf->release_callbacks, list) { + if (cb->callback) + cb->callback(cb->data); + list_del(&cb->list); + kfree(cb); + } + mutex_unlock(&dmabuf->release_lock); +#endif + dmabuf->ops->release(dmabuf); mutex_lock(&db_list.lock); @@ -457,6 +479,47 @@ err_alloc_file: return file; } +#ifdef CONFIG_ARCH_ROCKCHIP +void *dma_buf_get_release_callback_data(struct dma_buf *dmabuf, + void (*callback)(void *)) +{ + struct dma_buf_callback *cb, *tmp; + void *result = NULL; + + mutex_lock(&dmabuf->release_lock); + list_for_each_entry_safe(cb, tmp, &dmabuf->release_callbacks, list) { + if (cb->callback == callback) { + result = cb->data; + break; + } + } + mutex_unlock(&dmabuf->release_lock); + + return result; +} + +int dma_buf_set_release_callback(struct dma_buf *dmabuf, + void (*callback)(void *), void *data) +{ + struct dma_buf_callback *cb; + + if (WARN_ON(dma_buf_get_release_callback_data(dmabuf, callback))) + return -EINVAL; + + cb = kzalloc(sizeof(*cb), GFP_KERNEL); + if (!cb) + return -ENOMEM; + + cb->callback = callback; + cb->data = data; + mutex_lock(&dmabuf->release_lock); + list_add_tail(&cb->list, &dmabuf->release_callbacks); + mutex_unlock(&dmabuf->release_lock); + + return 0; +} +#endif + /** * DOC: dma buf device access * @@ -564,7 +627,10 @@ struct dma_buf *dma_buf_export(const struct dma_buf_export_info *exp_info) mutex_init(&dmabuf->lock); INIT_LIST_HEAD(&dmabuf->attachments); - +#ifdef CONFIG_ARCH_ROCKCHIP + mutex_init(&dmabuf->release_lock); + INIT_LIST_HEAD(&dmabuf->release_callbacks); +#endif mutex_lock(&db_list.lock); list_add(&dmabuf->list_node, &db_list.head); mutex_unlock(&db_list.lock); diff --git a/include/linux/dma-buf.h b/include/linux/dma-buf.h index 582998e19df6..267ec0d67fcb 100644 --- a/include/linux/dma-buf.h +++ b/include/linux/dma-buf.h @@ -146,7 +146,12 @@ struct dma_buf_ops { /* TODO: Add try_map_dma_buf version, to return immed with -EBUSY * if the call would block. */ - +#ifdef CONFIG_ARCH_ROCKCHIP + int (*set_release_callback)(void (*release_callback)(void *data), + void *data); + void *(*get_release_callback_data)(void *callback); + /* after final dma_buf_put() */ +#endif /** * @release: * @@ -283,6 +288,10 @@ struct dma_buf { size_t size; struct file *file; struct list_head attachments; +#ifdef CONFIG_ARCH_ROCKCHIP + struct list_head release_callbacks; + struct mutex release_lock; +#endif const struct dma_buf_ops *ops; struct mutex lock; unsigned vmapping_counter; @@ -376,6 +385,14 @@ static inline void get_dma_buf(struct dma_buf *dmabuf) get_file(dmabuf->file); } +#ifdef CONFIG_ARCH_ROCKCHIP +int dma_buf_set_release_callback(struct dma_buf *dmabuf, + void (*callback)(void *), void *data); + +void *dma_buf_get_release_callback_data(struct dma_buf *dmabuf, + void (*callback)(void *)); +#endif + struct dma_buf_attachment *dma_buf_attach(struct dma_buf *dmabuf, struct device *dev); void dma_buf_detach(struct dma_buf *dmabuf,