Commit 05b84911 authored by Rob Clark's avatar Rob Clark

drm/msm: prime support

Signed-off-by: default avatarRob Clark <robdclark@gmail.com>
Acked-by: default avatarDavid Brown <davidb@codeaurora.org>
parent 959f5854
...@@ -21,6 +21,7 @@ msm-y := \ ...@@ -21,6 +21,7 @@ msm-y := \
msm_drv.o \ msm_drv.o \
msm_fb.o \ msm_fb.o \
msm_gem.o \ msm_gem.o \
msm_gem_prime.o \
msm_gem_submit.o \ msm_gem_submit.o \
msm_gpu.o \ msm_gpu.o \
msm_ringbuffer.o msm_ringbuffer.o
......
...@@ -680,7 +680,10 @@ static const struct file_operations fops = { ...@@ -680,7 +680,10 @@ static const struct file_operations fops = {
}; };
static struct drm_driver msm_driver = { 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, .load = msm_load,
.unload = msm_unload, .unload = msm_unload,
.open = msm_open, .open = msm_open,
...@@ -698,6 +701,16 @@ static struct drm_driver msm_driver = { ...@@ -698,6 +701,16 @@ static struct drm_driver msm_driver = {
.dumb_create = msm_gem_dumb_create, .dumb_create = msm_gem_dumb_create,
.dumb_map_offset = msm_gem_dumb_map_offset, .dumb_map_offset = msm_gem_dumb_map_offset,
.dumb_destroy = drm_gem_dumb_destroy, .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 #ifdef CONFIG_DEBUG_FS
.debugfs_init = msm_debugfs_init, .debugfs_init = msm_debugfs_init,
.debugfs_cleanup = msm_debugfs_cleanup, .debugfs_cleanup = msm_debugfs_cleanup,
......
...@@ -141,13 +141,20 @@ uint64_t msm_gem_mmap_offset(struct drm_gem_object *obj); ...@@ -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, int msm_gem_get_iova_locked(struct drm_gem_object *obj, int id,
uint32_t *iova); uint32_t *iova);
int msm_gem_get_iova(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); 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, int msm_gem_dumb_create(struct drm_file *file, struct drm_device *dev,
struct drm_mode_create_dumb *args); 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, int msm_gem_dumb_map_offset(struct drm_file *file, struct drm_device *dev,
uint32_t handle, uint64_t *offset); 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_locked(struct drm_gem_object *obj);
void *msm_gem_vaddr(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, 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, ...@@ -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); uint32_t size, uint32_t flags, uint32_t *handle);
struct drm_gem_object *msm_gem_new(struct drm_device *dev, struct drm_gem_object *msm_gem_new(struct drm_device *dev,
uint32_t size, uint32_t flags); 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); struct drm_gem_object *msm_framebuffer_bo(struct drm_framebuffer *fb, int plane);
const struct msm_format *msm_framebuffer_format(struct drm_framebuffer *fb); const struct msm_format *msm_framebuffer_format(struct drm_framebuffer *fb);
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/shmem_fs.h> #include <linux/shmem_fs.h>
#include <linux/dma-buf.h>
#include "msm_drv.h" #include "msm_drv.h"
#include "msm_gem.h" #include "msm_gem.h"
...@@ -77,6 +78,21 @@ static void put_pages(struct drm_gem_object *obj) ...@@ -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, int msm_gem_mmap_obj(struct drm_gem_object *obj,
struct vm_area_struct *vma) struct vm_area_struct *vma)
{ {
...@@ -510,10 +526,21 @@ void msm_gem_free_object(struct drm_gem_object *obj) ...@@ -510,10 +526,21 @@ void msm_gem_free_object(struct drm_gem_object *obj)
drm_gem_free_mmap_offset(obj); drm_gem_free_mmap_offset(obj);
if (obj->import_attach) {
if (msm_obj->vaddr) if (msm_obj->vaddr)
vunmap(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);
} else {
if (msm_obj->vaddr)
vunmap(msm_obj->vaddr);
put_pages(obj); put_pages(obj);
}
if (msm_obj->resv == &msm_obj->_resv) if (msm_obj->resv == &msm_obj->_resv)
reservation_object_fini(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, ...@@ -549,17 +576,12 @@ int msm_gem_new_handle(struct drm_device *dev, struct drm_file *file,
return ret; return ret;
} }
struct drm_gem_object *msm_gem_new(struct drm_device *dev, static int msm_gem_new_impl(struct drm_device *dev,
uint32_t size, uint32_t flags) uint32_t size, uint32_t flags,
struct drm_gem_object **obj)
{ {
struct msm_drm_private *priv = dev->dev_private; struct msm_drm_private *priv = dev->dev_private;
struct msm_gem_object *msm_obj; 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) { switch (flags & MSM_BO_CACHE_MASK) {
case MSM_BO_UNCACHED: case MSM_BO_UNCACHED:
...@@ -569,21 +591,12 @@ struct drm_gem_object *msm_gem_new(struct drm_device *dev, ...@@ -569,21 +591,12 @@ struct drm_gem_object *msm_gem_new(struct drm_device *dev,
default: default:
dev_err(dev->dev, "invalid cache flag: %x\n", dev_err(dev->dev, "invalid cache flag: %x\n",
(flags & MSM_BO_CACHE_MASK)); (flags & MSM_BO_CACHE_MASK));
ret = -EINVAL; return -EINVAL;
goto fail;
} }
msm_obj = kzalloc(sizeof(*msm_obj), GFP_KERNEL); msm_obj = kzalloc(sizeof(*msm_obj), GFP_KERNEL);
if (!msm_obj) { if (!msm_obj)
ret = -ENOMEM; return -ENOMEM;
goto fail;
}
obj = &msm_obj->base;
ret = drm_gem_object_init(dev, obj, size);
if (ret)
goto fail;
msm_obj->flags = flags; msm_obj->flags = flags;
...@@ -594,6 +607,67 @@ struct drm_gem_object *msm_gem_new(struct drm_device *dev, ...@@ -594,6 +607,67 @@ struct drm_gem_object *msm_gem_new(struct drm_device *dev,
INIT_LIST_HEAD(&msm_obj->inactive_work); INIT_LIST_HEAD(&msm_obj->inactive_work);
list_add_tail(&msm_obj->mm_list, &priv->inactive_list); 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; return obj;
fail: fail:
......
/*
* 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);
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment