]> Pileus Git - ~andy/linux/commitdiff
drm/msm: prime support
authorRob Clark <robdclark@gmail.com>
Sat, 28 Sep 2013 15:28:35 +0000 (11:28 -0400)
committerRob Clark <robdclark@gmail.com>
Fri, 1 Nov 2013 16:39:44 +0000 (12:39 -0400)
Signed-off-by: Rob Clark <robdclark@gmail.com>
Acked-by: David Brown <davidb@codeaurora.org>
drivers/gpu/drm/msm/Makefile
drivers/gpu/drm/msm/msm_drv.c
drivers/gpu/drm/msm/msm_drv.h
drivers/gpu/drm/msm/msm_gem.c
drivers/gpu/drm/msm/msm_gem_prime.c [new file with mode: 0644]

index e17914889e545eb20f008450846c582e15aae211..e5fa12b0d21eca645a2cc5efa8f74bef595ad2bb 100644 (file)
@@ -21,6 +21,7 @@ msm-y := \
        msm_drv.o \
        msm_fb.o \
        msm_gem.o \
+       msm_gem_prime.o \
        msm_gem_submit.o \
        msm_gpu.o \
        msm_ringbuffer.o
index b3a2f16290417cb055a8d7d89dc8f3f876b3a090..cfeebdd911dd584226a9ea725fe6a065c3cb991a 100644 (file)
@@ -680,7 +680,10 @@ static const struct file_operations fops = {
 };
 
 static struct drm_driver msm_driver = {
-       .driver_features    = DRIVER_HAVE_IRQ | DRIVER_GEM | DRIVER_MODESET,
+       .driver_features    = DRIVER_HAVE_IRQ |
+                               DRIVER_GEM |
+                               DRIVER_PRIME |
+                               DRIVER_MODESET,
        .load               = msm_load,
        .unload             = msm_unload,
        .open               = msm_open,
@@ -698,6 +701,16 @@ static struct drm_driver msm_driver = {
        .dumb_create        = msm_gem_dumb_create,
        .dumb_map_offset    = msm_gem_dumb_map_offset,
        .dumb_destroy       = drm_gem_dumb_destroy,
+       .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
+       .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
+       .gem_prime_export   = drm_gem_prime_export,
+       .gem_prime_import   = drm_gem_prime_import,
+       .gem_prime_pin      = msm_gem_prime_pin,
+       .gem_prime_unpin    = msm_gem_prime_unpin,
+       .gem_prime_get_sg_table = msm_gem_prime_get_sg_table,
+       .gem_prime_import_sg_table = msm_gem_prime_import_sg_table,
+       .gem_prime_vmap     = msm_gem_prime_vmap,
+       .gem_prime_vunmap   = msm_gem_prime_vunmap,
 #ifdef CONFIG_DEBUG_FS
        .debugfs_init       = msm_debugfs_init,
        .debugfs_cleanup    = msm_debugfs_cleanup,
index df8f1d084bc1d76d1ee8dc5db948e7ebf9f87771..9ce90c267ef8a43f14578c5888e52a45c8090cff 100644 (file)
@@ -141,13 +141,20 @@ uint64_t msm_gem_mmap_offset(struct drm_gem_object *obj);
 int msm_gem_get_iova_locked(struct drm_gem_object *obj, int id,
                uint32_t *iova);
 int msm_gem_get_iova(struct drm_gem_object *obj, int id, uint32_t *iova);
+struct page **msm_gem_get_pages(struct drm_gem_object *obj);
+void msm_gem_put_pages(struct drm_gem_object *obj);
 void msm_gem_put_iova(struct drm_gem_object *obj, int id);
 int msm_gem_dumb_create(struct drm_file *file, struct drm_device *dev,
                struct drm_mode_create_dumb *args);
-int msm_gem_dumb_destroy(struct drm_file *file, struct drm_device *dev,
-               uint32_t handle);
 int msm_gem_dumb_map_offset(struct drm_file *file, struct drm_device *dev,
                uint32_t handle, uint64_t *offset);
+struct sg_table *msm_gem_prime_get_sg_table(struct drm_gem_object *obj);
+void *msm_gem_prime_vmap(struct drm_gem_object *obj);
+void msm_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr);
+struct drm_gem_object *msm_gem_prime_import_sg_table(struct drm_device *dev,
+               size_t size, struct sg_table *sg);
+int msm_gem_prime_pin(struct drm_gem_object *obj);
+void msm_gem_prime_unpin(struct drm_gem_object *obj);
 void *msm_gem_vaddr_locked(struct drm_gem_object *obj);
 void *msm_gem_vaddr(struct drm_gem_object *obj);
 int msm_gem_queue_inactive_work(struct drm_gem_object *obj,
@@ -163,6 +170,8 @@ int msm_gem_new_handle(struct drm_device *dev, struct drm_file *file,
                uint32_t size, uint32_t flags, uint32_t *handle);
 struct drm_gem_object *msm_gem_new(struct drm_device *dev,
                uint32_t size, uint32_t flags);
+struct drm_gem_object *msm_gem_import(struct drm_device *dev,
+               uint32_t size, struct sg_table *sgt);
 
 struct drm_gem_object *msm_framebuffer_bo(struct drm_framebuffer *fb, int plane);
 const struct msm_format *msm_framebuffer_format(struct drm_framebuffer *fb);
index 2bae46c66a30dd4c3eac623c07dbf55c70d32cb8..ea2c96f9459bf0095dd0ec7abf02831e7ac5630e 100644 (file)
@@ -17,6 +17,7 @@
 
 #include <linux/spinlock.h>
 #include <linux/shmem_fs.h>
+#include <linux/dma-buf.h>
 
 #include "msm_drv.h"
 #include "msm_gem.h"
@@ -77,6 +78,21 @@ static void put_pages(struct drm_gem_object *obj)
        }
 }
 
+struct page **msm_gem_get_pages(struct drm_gem_object *obj)
+{
+       struct drm_device *dev = obj->dev;
+       struct page **p;
+       mutex_lock(&dev->struct_mutex);
+       p = get_pages(obj);
+       mutex_unlock(&dev->struct_mutex);
+       return p;
+}
+
+void msm_gem_put_pages(struct drm_gem_object *obj)
+{
+       /* when we start tracking the pin count, then do something here */
+}
+
 int msm_gem_mmap_obj(struct drm_gem_object *obj,
                struct vm_area_struct *vma)
 {
@@ -510,10 +526,21 @@ void msm_gem_free_object(struct drm_gem_object *obj)
 
        drm_gem_free_mmap_offset(obj);
 
-       if (msm_obj->vaddr)
-               vunmap(msm_obj->vaddr);
+       if (obj->import_attach) {
+               if (msm_obj->vaddr)
+                       dma_buf_vunmap(obj->import_attach->dmabuf, msm_obj->vaddr);
+
+               /* Don't drop the pages for imported dmabuf, as they are not
+                * ours, just free the array we allocated:
+                */
+               if (msm_obj->pages)
+                       drm_free_large(msm_obj->pages);
 
-       put_pages(obj);
+       } else {
+               if (msm_obj->vaddr)
+                       vunmap(msm_obj->vaddr);
+               put_pages(obj);
+       }
 
        if (msm_obj->resv == &msm_obj->_resv)
                reservation_object_fini(msm_obj->resv);
@@ -549,17 +576,12 @@ int msm_gem_new_handle(struct drm_device *dev, struct drm_file *file,
        return ret;
 }
 
-struct drm_gem_object *msm_gem_new(struct drm_device *dev,
-               uint32_t size, uint32_t flags)
+static int msm_gem_new_impl(struct drm_device *dev,
+               uint32_t size, uint32_t flags,
+               struct drm_gem_object **obj)
 {
        struct msm_drm_private *priv = dev->dev_private;
        struct msm_gem_object *msm_obj;
-       struct drm_gem_object *obj = NULL;
-       int ret;
-
-       WARN_ON(!mutex_is_locked(&dev->struct_mutex));
-
-       size = PAGE_ALIGN(size);
 
        switch (flags & MSM_BO_CACHE_MASK) {
        case MSM_BO_UNCACHED:
@@ -569,21 +591,12 @@ struct drm_gem_object *msm_gem_new(struct drm_device *dev,
        default:
                dev_err(dev->dev, "invalid cache flag: %x\n",
                                (flags & MSM_BO_CACHE_MASK));
-               ret = -EINVAL;
-               goto fail;
+               return -EINVAL;
        }
 
        msm_obj = kzalloc(sizeof(*msm_obj), GFP_KERNEL);
-       if (!msm_obj) {
-               ret = -ENOMEM;
-               goto fail;
-       }
-
-       obj = &msm_obj->base;
-
-       ret = drm_gem_object_init(dev, obj, size);
-       if (ret)
-               goto fail;
+       if (!msm_obj)
+               return -ENOMEM;
 
        msm_obj->flags = flags;
 
@@ -594,6 +607,67 @@ struct drm_gem_object *msm_gem_new(struct drm_device *dev,
        INIT_LIST_HEAD(&msm_obj->inactive_work);
        list_add_tail(&msm_obj->mm_list, &priv->inactive_list);
 
+       *obj = &msm_obj->base;
+
+       return 0;
+}
+
+struct drm_gem_object *msm_gem_new(struct drm_device *dev,
+               uint32_t size, uint32_t flags)
+{
+       struct drm_gem_object *obj;
+       int ret;
+
+       WARN_ON(!mutex_is_locked(&dev->struct_mutex));
+
+       size = PAGE_ALIGN(size);
+
+       ret = msm_gem_new_impl(dev, size, flags, &obj);
+       if (ret)
+               goto fail;
+
+       ret = drm_gem_object_init(dev, obj, size);
+       if (ret)
+               goto fail;
+
+       return obj;
+
+fail:
+       if (obj)
+               drm_gem_object_unreference_unlocked(obj);
+
+       return ERR_PTR(ret);
+}
+
+struct drm_gem_object *msm_gem_import(struct drm_device *dev,
+               uint32_t size, struct sg_table *sgt)
+{
+       struct msm_gem_object *msm_obj;
+       struct drm_gem_object *obj;
+       int ret, npages;
+
+       size = PAGE_ALIGN(size);
+
+       ret = msm_gem_new_impl(dev, size, MSM_BO_WC, &obj);
+       if (ret)
+               goto fail;
+
+       drm_gem_private_object_init(dev, obj, size);
+
+       npages = size / PAGE_SIZE;
+
+       msm_obj = to_msm_bo(obj);
+       msm_obj->sgt = sgt;
+       msm_obj->pages = drm_malloc_ab(npages, sizeof(struct page *));
+       if (!msm_obj->pages) {
+               ret = -ENOMEM;
+               goto fail;
+       }
+
+       ret = drm_prime_sg_to_page_addr_arrays(sgt, msm_obj->pages, NULL, npages);
+       if (ret)
+               goto fail;
+
        return obj;
 
 fail:
diff --git a/drivers/gpu/drm/msm/msm_gem_prime.c b/drivers/gpu/drm/msm/msm_gem_prime.c
new file mode 100644 (file)
index 0000000..d48f9fc
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2013 Red Hat
+ * Author: Rob Clark <robdclark@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "msm_drv.h"
+#include "msm_gem.h"
+
+
+struct sg_table *msm_gem_prime_get_sg_table(struct drm_gem_object *obj)
+{
+       struct msm_gem_object *msm_obj = to_msm_bo(obj);
+       BUG_ON(!msm_obj->sgt);  /* should have already pinned! */
+       return msm_obj->sgt;
+}
+
+void *msm_gem_prime_vmap(struct drm_gem_object *obj)
+{
+       return msm_gem_vaddr(obj);
+}
+
+void msm_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr)
+{
+       /* TODO msm_gem_vunmap() */
+}
+
+struct drm_gem_object *msm_gem_prime_import_sg_table(struct drm_device *dev,
+               size_t size, struct sg_table *sg)
+{
+       return msm_gem_import(dev, size, sg);
+}
+
+int msm_gem_prime_pin(struct drm_gem_object *obj)
+{
+       if (!obj->import_attach)
+               msm_gem_get_pages(obj);
+       return 0;
+}
+
+void msm_gem_prime_unpin(struct drm_gem_object *obj)
+{
+       if (!obj->import_attach)
+               msm_gem_put_pages(obj);
+}