drm/msm: prime support
Signed-off-by: Rob Clark <robdclark@gmail.com> Acked-by: David Brown <davidb@codeaurora.org>
This commit is contained in:
Родитель
959f58544b
Коммит
05b849111c
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
put_pages(obj);
|
||||
/* 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);
|
||||
}
|
||||
|
||||
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:
|
||||
|
|
|
@ -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);
|
||||
}
|
Загрузка…
Ссылка в новой задаче