drm/drm-prime: cache dma_buf import context
authorMark Yao <mark.yao@rock-chips.com>
Mon, 20 Mar 2017 02:31:02 +0000 (10:31 +0800)
committerHuang, Tao <huangtao@rock-chips.com>
Thu, 23 Mar 2017 10:20:05 +0000 (18:20 +0800)
Change-Id: Ia39a3d4691f0b545039efb880c999a35886178a0
Signed-off-by: Mark Yao <mark.yao@rock-chips.com>
drivers/gpu/drm/drm_prime.c
drivers/gpu/drm/rockchip/rockchip_drm_gem.c

index 4675bd3..3331c56 100644 (file)
@@ -71,6 +71,11 @@ struct drm_prime_attachment {
        enum dma_data_direction dir;
 };
 
+struct drm_prime_callback_data {
+       struct drm_gem_object *obj;
+       struct sg_table *sgt;
+};
+
 static int drm_prime_add_buf_handle(struct drm_prime_file_private *prime_fpriv,
                                    struct dma_buf *dma_buf, uint32_t handle)
 {
@@ -491,6 +496,23 @@ out_unlock:
 }
 EXPORT_SYMBOL(drm_gem_prime_handle_to_fd);
 
+static void drm_gem_prime_dmabuf_release_callback(void *data)
+{
+       struct drm_prime_callback_data *cb_data = data;
+
+       if (cb_data && cb_data->obj && cb_data->obj->import_attach) {
+               struct dma_buf_attachment *attach = cb_data->obj->import_attach;
+               struct sg_table *sgt = cb_data->sgt;
+
+               if (sgt)
+                       dma_buf_unmap_attachment(attach, sgt,
+                                                DMA_BIDIRECTIONAL);
+               dma_buf_detach(attach->dmabuf, attach);
+               drm_gem_object_unreference_unlocked(cb_data->obj);
+               kfree(cb_data);
+       }
+}
+
 /**
  * drm_gem_prime_import - helper library implementation of the import callback
  * @dev: drm_device to import into
@@ -505,6 +527,7 @@ struct drm_gem_object *drm_gem_prime_import(struct drm_device *dev,
        struct dma_buf_attachment *attach;
        struct sg_table *sgt;
        struct drm_gem_object *obj;
+       struct drm_prime_callback_data *cb_data;
        int ret;
 
        if (dma_buf->ops == &drm_gem_prime_dmabuf_ops) {
@@ -519,6 +542,13 @@ struct drm_gem_object *drm_gem_prime_import(struct drm_device *dev,
                }
        }
 
+       cb_data = dma_buf_get_release_callback_data(dma_buf,
+                                       drm_gem_prime_dmabuf_release_callback);
+       if (cb_data && cb_data->obj && cb_data->obj->dev == dev) {
+               drm_gem_object_reference(cb_data->obj);
+               return cb_data->obj;
+       }
+
        if (!dev->driver->gem_prime_import_sg_table)
                return ERR_PTR(-EINVAL);
 
@@ -527,11 +557,16 @@ struct drm_gem_object *drm_gem_prime_import(struct drm_device *dev,
                return ERR_CAST(attach);
 
        get_dma_buf(dma_buf);
+       cb_data = kmalloc(sizeof(*cb_data), GFP_KERNEL);
+       if (!cb_data) {
+               ret = -ENOMEM;
+               goto fail_detach;
+       }
 
        sgt = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL);
        if (IS_ERR(sgt)) {
                ret = PTR_ERR(sgt);
-               goto fail_detach;
+               goto fail_free;
        }
 
        obj = dev->driver->gem_prime_import_sg_table(dev, attach, sgt);
@@ -539,13 +574,20 @@ struct drm_gem_object *drm_gem_prime_import(struct drm_device *dev,
                ret = PTR_ERR(obj);
                goto fail_unmap;
        }
-
        obj->import_attach = attach;
+       cb_data->obj = obj;
+       cb_data->sgt = sgt;
+       dma_buf_set_release_callback(dma_buf,
+                       drm_gem_prime_dmabuf_release_callback, cb_data);
+       dma_buf_put(dma_buf);
+       drm_gem_object_reference(obj);
 
        return obj;
 
 fail_unmap:
        dma_buf_unmap_attachment(attach, sgt, DMA_BIDIRECTIONAL);
+fail_free:
+       kfree(cb_data);
 fail_detach:
        dma_buf_detach(dma_buf, attach);
        dma_buf_put(dma_buf);
index 30d8efc..12bc70d 100644 (file)
@@ -493,7 +493,6 @@ void rockchip_gem_free_object(struct drm_gem_object *obj)
                        dma_unmap_sg(drm->dev, rk_obj->sgt->sgl,
                                     rk_obj->sgt->nents, DMA_BIDIRECTIONAL);
                }
-               drm_prime_gem_destroy(obj, rk_obj->sgt);
        } else {
                rockchip_gem_free_buf(rk_obj);
        }