<div dir="ltr">Sorry I forgot to remove the Change-Id lines for these 2 patches. Please review and I'll send updated patches with the Change-Id lines removed.<br><div class="gmail_extra"><br><div class="gmail_quote">On Wed, Nov 12, 2014 at 6:33 PM, Haixia Shi <span dir="ltr"><<a href="mailto:hshi@chromium.org" target="_blank">hshi@chromium.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Only importing an FD to a handle is currently supported on UDL,<br>
but the exporting functionality is equally useful.<br>
<br>
Change-Id: If4983041875ebf3bd2ecf996d0771eb77b0cf1dc<br>
Signed-off-by: Haixia Shi <<a href="mailto:hshi@chromium.org">hshi@chromium.org</a>><br>
Reviewed-by: Stéphane Marchesin <<a href="mailto:marcheu@chromium.org">marcheu@chromium.org</a>><br>
---<br>
 drivers/gpu/drm/udl/Makefile     |   2 +-<br>
 drivers/gpu/drm/udl/udl_dmabuf.c | 273 +++++++++++++++++++++++++++++++++++++++<br>
 drivers/gpu/drm/udl/udl_drv.c    |   2 +<br>
 drivers/gpu/drm/udl/udl_drv.h    |   2 +<br>
 drivers/gpu/drm/udl/udl_gem.c    |  71 ----------<br>
 5 files changed, 278 insertions(+), 72 deletions(-)<br>
 create mode 100644 drivers/gpu/drm/udl/udl_dmabuf.c<br>
<br>
diff --git a/drivers/gpu/drm/udl/Makefile b/drivers/gpu/drm/udl/Makefile<br>
index 05c7481..195bcac 100644<br>
--- a/drivers/gpu/drm/udl/Makefile<br>
+++ b/drivers/gpu/drm/udl/Makefile<br>
@@ -1,6 +1,6 @@<br>
<br>
 ccflags-y := -Iinclude/drm<br>
<br>
-udl-y := udl_drv.o udl_modeset.o udl_connector.o udl_encoder.o udl_main.o udl_fb.o udl_transfer.o udl_gem.o<br>
+udl-y := udl_drv.o udl_modeset.o udl_connector.o udl_encoder.o udl_main.o udl_fb.o udl_transfer.o udl_gem.o udl_dmabuf.o<br>
<br>
 obj-$(CONFIG_DRM_UDL) := udl.o<br>
diff --git a/drivers/gpu/drm/udl/udl_dmabuf.c b/drivers/gpu/drm/udl/udl_dmabuf.c<br>
new file mode 100644<br>
index 0000000..1d85c3a<br>
--- /dev/null<br>
+++ b/drivers/gpu/drm/udl/udl_dmabuf.c<br>
@@ -0,0 +1,273 @@<br>
+/*<br>
+ * udl_dmabuf.c<br>
+ *<br>
+ * Copyright (c) 2014 The Chromium OS Authors<br>
+ *<br>
+ * This program is free software; you can redistribute  it and/or modify it<br>
+ * under  the terms of  the GNU General  Public License as published by the<br>
+ * Free Software Foundation;  either version 2 of the  License, or (at your<br>
+ * option) any later version.<br>
+ *<br>
+ * This program is distributed in the hope that it will be useful,<br>
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of<br>
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the<br>
+ * GNU General Public License for more details.<br>
+ *<br>
+ * You should have received a copy of the GNU General Public License<br>
+ * along with this program. If not, see <<a href="http://www.gnu.org/licenses/" target="_blank">http://www.gnu.org/licenses/</a>>.<br>
+ */<br>
+<br>
+#include <drm/drmP.h><br>
+#include "udl_drv.h"<br>
+#include <linux/shmem_fs.h><br>
+#include <linux/dma-buf.h><br>
+<br>
+struct udl_drm_dmabuf_attachment {<br>
+       struct sg_table sgt;<br>
+       enum dma_data_direction dir;<br>
+       bool is_mapped;<br>
+};<br>
+<br>
+static int udl_attach_dma_buf(struct dma_buf *dmabuf,<br>
+                             struct device *dev,<br>
+                             struct dma_buf_attachment *attach)<br>
+{<br>
+       struct udl_drm_dmabuf_attachment *udl_attach;<br>
+<br>
+       DRM_DEBUG_PRIME("[DEV:%s] size:%zd\n", dev_name(attach->dev),<br>
+                       attach->dmabuf->size);<br>
+<br>
+       udl_attach = kzalloc(sizeof(*udl_attach), GFP_KERNEL);<br>
+       if (!udl_attach)<br>
+               return -ENOMEM;<br>
+<br>
+       udl_attach->dir = DMA_NONE;<br>
+       attach->priv = udl_attach;<br>
+<br>
+       return 0;<br>
+}<br>
+<br>
+static void udl_detach_dma_buf(struct dma_buf *dmabuf,<br>
+                              struct dma_buf_attachment *attach)<br>
+{<br>
+       struct udl_drm_dmabuf_attachment *udl_attach = attach->priv;<br>
+       struct sg_table *sgt;<br>
+<br>
+       if (!udl_attach)<br>
+               return;<br>
+<br>
+       DRM_DEBUG_PRIME("[DEV:%s] size:%zd\n", dev_name(attach->dev),<br>
+                       attach->dmabuf->size);<br>
+<br>
+       sgt = &udl_attach->sgt;<br>
+<br>
+       if (udl_attach->dir != DMA_NONE)<br>
+               dma_unmap_sg(attach->dev, sgt->sgl, sgt->nents,<br>
+                               udl_attach->dir);<br>
+<br>
+       sg_free_table(sgt);<br>
+       kfree(udl_attach);<br>
+       attach->priv = NULL;<br>
+}<br>
+<br>
+static struct sg_table *udl_map_dma_buf(struct dma_buf_attachment *attach,<br>
+                                       enum dma_data_direction dir)<br>
+{<br>
+       struct udl_drm_dmabuf_attachment *udl_attach = attach->priv;<br>
+       struct udl_gem_object *obj = to_udl_bo(attach->dmabuf->priv);<br>
+       struct drm_device *dev = obj->base.dev;<br>
+       struct scatterlist *rd, *wr;<br>
+       struct sg_table *sgt = NULL;<br>
+       unsigned int i;<br>
+       int page_count;<br>
+       int nents, ret;<br>
+<br>
+       DRM_DEBUG_PRIME("[DEV:%s] size:%zd dir=%d\n", dev_name(attach->dev),<br>
+                       attach->dmabuf->size, dir);<br>
+<br>
+       /* just return current sgt if already requested. */<br>
+       if (udl_attach->dir == dir && udl_attach->is_mapped)<br>
+               return &udl_attach->sgt;<br>
+<br>
+       if (!obj->pages) {<br>
+               DRM_ERROR("pages is null.\n");<br>
+               return ERR_PTR(-ENOMEM);<br>
+       }<br>
+<br>
+       page_count = obj->base.size / PAGE_SIZE;<br>
+       obj->sg = drm_prime_pages_to_sg(obj->pages, page_count);<br>
+       if (!obj->sg) {<br>
+               DRM_ERROR("sg is null.\n");<br>
+               return ERR_PTR(-ENOMEM);<br>
+       }<br>
+<br>
+       sgt = &udl_attach->sgt;<br>
+<br>
+       ret = sg_alloc_table(sgt, obj->sg->orig_nents, GFP_KERNEL);<br>
+       if (ret) {<br>
+               DRM_ERROR("failed to alloc sgt.\n");<br>
+               return ERR_PTR(-ENOMEM);<br>
+       }<br>
+<br>
+       mutex_lock(&dev->struct_mutex);<br>
+<br>
+       rd = obj->sg->sgl;<br>
+       wr = sgt->sgl;<br>
+       for (i = 0; i < sgt->orig_nents; ++i) {<br>
+               sg_set_page(wr, sg_page(rd), rd->length, rd->offset);<br>
+               rd = sg_next(rd);<br>
+               wr = sg_next(wr);<br>
+       }<br>
+<br>
+       if (dir != DMA_NONE) {<br>
+               nents = dma_map_sg(attach->dev, sgt->sgl, sgt->orig_nents, dir);<br>
+               if (!nents) {<br>
+                       DRM_ERROR("failed to map sgl with iommu.\n");<br>
+                       sg_free_table(sgt);<br>
+                       sgt = ERR_PTR(-EIO);<br>
+                       goto err_unlock;<br>
+               }<br>
+       }<br>
+<br>
+       udl_attach->is_mapped = true;<br>
+       udl_attach->dir = dir;<br>
+       attach->priv = udl_attach;<br>
+<br>
+err_unlock:<br>
+       mutex_unlock(&dev->struct_mutex);<br>
+       return sgt;<br>
+}<br>
+<br>
+static void udl_unmap_dma_buf(struct dma_buf_attachment *attach,<br>
+                             struct sg_table *sgt,<br>
+                             enum dma_data_direction dir)<br>
+{<br>
+       /* Nothing to do. */<br>
+       DRM_DEBUG_PRIME("[DEV:%s] size:%zd dir:%d\n", dev_name(attach->dev),<br>
+                       attach->dmabuf->size, dir);<br>
+}<br>
+<br>
+static void *udl_dmabuf_kmap(struct dma_buf *dma_buf, unsigned long page_num)<br>
+{<br>
+       /* TODO */<br>
+<br>
+       return NULL;<br>
+}<br>
+<br>
+static void *udl_dmabuf_kmap_atomic(struct dma_buf *dma_buf,<br>
+                                   unsigned long page_num)<br>
+{<br>
+       /* TODO */<br>
+<br>
+       return NULL;<br>
+}<br>
+<br>
+static void udl_dmabuf_kunmap(struct dma_buf *dma_buf,<br>
+                             unsigned long page_num, void *addr)<br>
+{<br>
+       /* TODO */<br>
+}<br>
+<br>
+static void udl_dmabuf_kunmap_atomic(struct dma_buf *dma_buf,<br>
+                                    unsigned long page_num,<br>
+                                    void *addr)<br>
+{<br>
+       /* TODO */<br>
+}<br>
+<br>
+static int udl_dmabuf_mmap(struct dma_buf *dma_buf,<br>
+                          struct vm_area_struct *vma)<br>
+{<br>
+       /* TODO */<br>
+<br>
+       return -EINVAL;<br>
+}<br>
+<br>
+static struct dma_buf_ops udl_dmabuf_ops = {<br>
+       .attach                 = udl_attach_dma_buf,<br>
+       .detach                 = udl_detach_dma_buf,<br>
+       .map_dma_buf            = udl_map_dma_buf,<br>
+       .unmap_dma_buf          = udl_unmap_dma_buf,<br>
+       .kmap                   = udl_dmabuf_kmap,<br>
+       .kmap_atomic            = udl_dmabuf_kmap_atomic,<br>
+       .kunmap                 = udl_dmabuf_kunmap,<br>
+       .kunmap_atomic          = udl_dmabuf_kunmap_atomic,<br>
+       .mmap                   = udl_dmabuf_mmap,<br>
+       .release                = drm_gem_dmabuf_release,<br>
+};<br>
+<br>
+struct dma_buf *udl_gem_prime_export(struct drm_device *dev,<br>
+                                    struct drm_gem_object *obj, int flags)<br>
+{<br>
+       return dma_buf_export(obj, &udl_dmabuf_ops, obj->size, flags, NULL);<br>
+}<br>
+<br>
+static int udl_prime_create(struct drm_device *dev,<br>
+                           size_t size,<br>
+                           struct sg_table *sg,<br>
+                           struct udl_gem_object **obj_p)<br>
+{<br>
+       struct udl_gem_object *obj;<br>
+       int npages;<br>
+<br>
+       npages = size / PAGE_SIZE;<br>
+<br>
+       *obj_p = NULL;<br>
+       obj = udl_gem_alloc_object(dev, npages * PAGE_SIZE);<br>
+       if (!obj)<br>
+               return -ENOMEM;<br>
+<br>
+       obj->sg = sg;<br>
+       obj->pages = drm_malloc_ab(npages, sizeof(struct page *));<br>
+       if (obj->pages == NULL) {<br>
+               DRM_ERROR("obj pages is NULL %d\n", npages);<br>
+               return -ENOMEM;<br>
+       }<br>
+<br>
+       drm_prime_sg_to_page_addr_arrays(sg, obj->pages, NULL, npages);<br>
+<br>
+       *obj_p = obj;<br>
+       return 0;<br>
+}<br>
+<br>
+struct drm_gem_object *udl_gem_prime_import(struct drm_device *dev,<br>
+                               struct dma_buf *dma_buf)<br>
+{<br>
+       struct dma_buf_attachment *attach;<br>
+       struct sg_table *sg;<br>
+       struct udl_gem_object *uobj;<br>
+       int ret;<br>
+<br>
+       /* need to attach */<br>
+       get_device(dev->dev);<br>
+       attach = dma_buf_attach(dma_buf, dev->dev);<br>
+       if (IS_ERR(attach)) {<br>
+               put_device(dev->dev);<br>
+               return ERR_CAST(attach);<br>
+       }<br>
+<br>
+       get_dma_buf(dma_buf);<br>
+<br>
+       sg = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL);<br>
+       if (IS_ERR(sg)) {<br>
+               ret = PTR_ERR(sg);<br>
+               goto fail_detach;<br>
+       }<br>
+<br>
+       ret = udl_prime_create(dev, dma_buf->size, sg, &uobj);<br>
+       if (ret)<br>
+               goto fail_unmap;<br>
+<br>
+       uobj->base.import_attach = attach;<br>
+       uobj->flags = UDL_BO_WC;<br>
+<br>
+       return &uobj->base;<br>
+<br>
+fail_unmap:<br>
+       dma_buf_unmap_attachment(attach, sg, DMA_BIDIRECTIONAL);<br>
+fail_detach:<br>
+       dma_buf_detach(dma_buf, attach);<br>
+       dma_buf_put(dma_buf);<br>
+       put_device(dev->dev);<br>
+       return ERR_PTR(ret);<br>
+}<br>
diff --git a/drivers/gpu/drm/udl/udl_drv.c b/drivers/gpu/drm/udl/udl_drv.c<br>
index 8607e9e..d5728ec 100644<br>
--- a/drivers/gpu/drm/udl/udl_drv.c<br>
+++ b/drivers/gpu/drm/udl/udl_drv.c<br>
@@ -51,7 +51,9 @@ static struct drm_driver driver = {<br>
        .dumb_destroy = drm_gem_dumb_destroy,<br>
        .fops = &udl_driver_fops,<br>
<br>
+       .prime_handle_to_fd = drm_gem_prime_handle_to_fd,<br>
        .prime_fd_to_handle = drm_gem_prime_fd_to_handle,<br>
+       .gem_prime_export = udl_gem_prime_export,<br>
        .gem_prime_import = udl_gem_prime_import,<br>
<br>
        .name = DRIVER_NAME,<br>
diff --git a/drivers/gpu/drm/udl/udl_drv.h b/drivers/gpu/drm/udl/udl_drv.h<br>
index 3082780..1b132d7 100644<br>
--- a/drivers/gpu/drm/udl/udl_drv.h<br>
+++ b/drivers/gpu/drm/udl/udl_drv.h<br>
@@ -124,6 +124,8 @@ int udl_gem_mmap(struct drm_file *file_priv, struct drm_device *dev,<br>
 void udl_gem_free_object(struct drm_gem_object *gem_obj);<br>
 struct udl_gem_object *udl_gem_alloc_object(struct drm_device *dev,<br>
                                            size_t size);<br>
+struct dma_buf *udl_gem_prime_export(struct drm_device *dev,<br>
+                                    struct drm_gem_object *obj, int flags);<br>
 struct drm_gem_object *udl_gem_prime_import(struct drm_device *dev,<br>
                                struct dma_buf *dma_buf);<br>
<br>
diff --git a/drivers/gpu/drm/udl/udl_gem.c b/drivers/gpu/drm/udl/udl_gem.c<br>
index e00459d..692d6f2 100644<br>
--- a/drivers/gpu/drm/udl/udl_gem.c<br>
+++ b/drivers/gpu/drm/udl/udl_gem.c<br>
@@ -240,74 +240,3 @@ unlock:<br>
        mutex_unlock(&dev->struct_mutex);<br>
        return ret;<br>
 }<br>
-<br>
-static int udl_prime_create(struct drm_device *dev,<br>
-                           size_t size,<br>
-                           struct sg_table *sg,<br>
-                           struct udl_gem_object **obj_p)<br>
-{<br>
-       struct udl_gem_object *obj;<br>
-       int npages;<br>
-<br>
-       npages = size / PAGE_SIZE;<br>
-<br>
-       *obj_p = NULL;<br>
-       obj = udl_gem_alloc_object(dev, npages * PAGE_SIZE);<br>
-       if (!obj)<br>
-               return -ENOMEM;<br>
-<br>
-       obj->sg = sg;<br>
-       obj->pages = drm_malloc_ab(npages, sizeof(struct page *));<br>
-       if (obj->pages == NULL) {<br>
-               DRM_ERROR("obj pages is NULL %d\n", npages);<br>
-               return -ENOMEM;<br>
-       }<br>
-<br>
-       drm_prime_sg_to_page_addr_arrays(sg, obj->pages, NULL, npages);<br>
-<br>
-       *obj_p = obj;<br>
-       return 0;<br>
-}<br>
-<br>
-struct drm_gem_object *udl_gem_prime_import(struct drm_device *dev,<br>
-                               struct dma_buf *dma_buf)<br>
-{<br>
-       struct dma_buf_attachment *attach;<br>
-       struct sg_table *sg;<br>
-       struct udl_gem_object *uobj;<br>
-       int ret;<br>
-<br>
-       /* need to attach */<br>
-       get_device(dev->dev);<br>
-       attach = dma_buf_attach(dma_buf, dev->dev);<br>
-       if (IS_ERR(attach)) {<br>
-               put_device(dev->dev);<br>
-               return ERR_CAST(attach);<br>
-       }<br>
-<br>
-       get_dma_buf(dma_buf);<br>
-<br>
-       sg = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL);<br>
-       if (IS_ERR(sg)) {<br>
-               ret = PTR_ERR(sg);<br>
-               goto fail_detach;<br>
-       }<br>
-<br>
-       ret = udl_prime_create(dev, dma_buf->size, sg, &uobj);<br>
-       if (ret) {<br>
-               goto fail_unmap;<br>
-       }<br>
-<br>
-       uobj->base.import_attach = attach;<br>
-       uobj->flags = UDL_BO_WC;<br>
-<br>
-       return &uobj->base;<br>
-<br>
-fail_unmap:<br>
-       dma_buf_unmap_attachment(attach, sg, DMA_BIDIRECTIONAL);<br>
-fail_detach:<br>
-       dma_buf_detach(dma_buf, attach);<br>
-       dma_buf_put(dma_buf);<br>
-       put_device(dev->dev);<br>
-       return ERR_PTR(ret);<br>
-}<br>
<span class="HOEnZb"><font color="#888888">--<br>
2.1.0.rc2.206.gedb03e5<br>
<br>
</font></span></blockquote></div><br></div></div>