drm/msm: prime support
Signed-off-by: Rob Clark <robdclark@gmail.com> Acked-by: David Brown <davidb@codeaurora.org>
This commit is contained in:
parent
959f58544b
commit
05b849111c
5 changed files with 179 additions and 26 deletions
|
@ -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 = {
|
||||||
};
|
};
|
||||||
|
|
||||||
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 = {
|
||||||
.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);
|
||||||
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,
|
||||||
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 @@
|
||||||
|
|
||||||
#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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
drm_gem_free_mmap_offset(obj);
|
drm_gem_free_mmap_offset(obj);
|
||||||
|
|
||||||
if (msm_obj->vaddr)
|
if (obj->import_attach) {
|
||||||
vunmap(msm_obj->vaddr);
|
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)
|
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,
|
||||||
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,
|
||||||
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,
|
||||||
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:
|
||||||
|
|
56
drivers/gpu/drm/msm/msm_gem_prime.c
Normal file
56
drivers/gpu/drm/msm/msm_gem_prime.c
Normal file
|
@ -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);
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue