summaryrefslogtreecommitdiffstats
path: root/drm-vgem.patch
diff options
context:
space:
mode:
Diffstat (limited to 'drm-vgem.patch')
-rw-r--r--drm-vgem.patch492
1 files changed, 492 insertions, 0 deletions
diff --git a/drm-vgem.patch b/drm-vgem.patch
new file mode 100644
index 000000000..3610c8ba9
--- /dev/null
+++ b/drm-vgem.patch
@@ -0,0 +1,492 @@
+diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
+index 2418429..566c468 100644
+--- a/drivers/gpu/drm/Kconfig
++++ b/drivers/gpu/drm/Kconfig
+@@ -159,6 +159,14 @@ config DRM_SAVAGE
+ Choose this option if you have a Savage3D/4/SuperSavage/Pro/Twister
+ chipset. If M is selected the module will be called savage.
+
++config DRM_VGEM
++ tristate "Virtual GEM provider"
++ depends on DRM
++ help
++ Choose this option to get a virtual graphics memory manager,
++ as used by Mesa's software renderer for enhanced performance.
++ If M is selected the module will be called vgem.
++
+ source "drivers/gpu/drm/exynos/Kconfig"
+
+ source "drivers/gpu/drm/vmwgfx/Kconfig"
+diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
+index 0cde1b8..021bf8a 100644
+--- a/drivers/gpu/drm/Makefile
++++ b/drivers/gpu/drm/Makefile
+@@ -34,6 +34,7 @@ obj-$(CONFIG_DRM_SIS) += sis/
+ obj-$(CONFIG_DRM_SAVAGE)+= savage/
+ obj-$(CONFIG_DRM_VMWGFX)+= vmwgfx/
+ obj-$(CONFIG_DRM_VIA) +=via/
++obj-$(CONFIG_DRM_VGEM) += vgem/
+ obj-$(CONFIG_DRM_NOUVEAU) +=nouveau/
+ obj-$(CONFIG_DRM_EXYNOS) +=exynos/
+ obj-$(CONFIG_DRM_GMA500) += gma500/
+diff --git a/drivers/gpu/drm/vgem/Makefile b/drivers/gpu/drm/vgem/Makefile
+new file mode 100644
+index 0000000..3f4c7b8
+--- /dev/null
++++ b/drivers/gpu/drm/vgem/Makefile
+@@ -0,0 +1,4 @@
++ccflags-y := -Iinclude/drm
++vgem-y := vgem_drv.o
++
++obj-$(CONFIG_DRM_VGEM) += vgem.o
+diff --git a/drivers/gpu/drm/vgem/vgem_drv.c b/drivers/gpu/drm/vgem/vgem_drv.c
+new file mode 100644
+index 0000000..16f88ee
+--- /dev/null
++++ b/drivers/gpu/drm/vgem/vgem_drv.c
+@@ -0,0 +1,377 @@
++/*
++ * Copyright 2011 Red Hat, Inc.
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the "Software")
++ * to deal in the software without restriction, including without limitation
++ * on the rights to use, copy, modify, merge, publish, distribute, sub
++ * license, and/or sell copies of the Software, and to permit persons to whom
++ * them Software is furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice (including the next
++ * paragraph) shall be included in all copies or substantial portions of the
++ * Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTIBILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
++ * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY, WHETHER
++ * IN AN ACTION OF CONTRACT, TORT, OR OTHERWISE, ARISING FROM, OUT OF OR IN
++ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
++ *
++ * Authors:
++ * Adam Jackson <ajax@redhat.com>
++ */
++
++/**
++ * This is vgem, a (non-hardware-backed) GEM service. This is used by Mesa's
++ * software renderer and the X server for efficient buffer sharing.
++ */
++
++#include "drmP.h"
++#include "drm.h"
++#include "vgem_drm.h"
++#include <linux/module.h>
++#include <linux/ramfs.h>
++#include <linux/shmem_fs.h>
++
++#define DRIVER_NAME "vgem"
++#define DRIVER_DESC "Virtual GEM provider"
++#define DRIVER_DATE "20120112"
++#define DRIVER_MAJOR 1
++#define DRIVER_MINOR 0
++
++#define to_vgem_bo(x) container_of(x, struct drm_vgem_gem_object, base)
++
++struct drm_vgem_gem_object {
++ struct drm_gem_object base;
++ struct page **pages;
++};
++
++static int vgem_load(struct drm_device *dev, unsigned long flags)
++{
++ return 0;
++}
++
++static int vgem_unload(struct drm_device *dev)
++{
++ return 0;
++}
++
++static void vgem_preclose(struct drm_device *dev, struct drm_file *file)
++{
++}
++
++static void vgem_lastclose(struct drm_device *dev)
++{
++}
++
++static int vgem_gem_init_object(struct drm_gem_object *obj)
++{
++ return 0;
++}
++
++static void vgem_gem_put_pages(struct drm_vgem_gem_object *obj)
++{
++ int num_pages = obj->base.size / PAGE_SIZE;
++ int i;
++
++ for (i = 0; i < num_pages; i++) {
++ page_cache_release(obj->pages[i]);
++ }
++
++ drm_free_large(obj->pages);
++ obj->pages = NULL;
++}
++
++static void vgem_gem_free_object(struct drm_gem_object *obj)
++{
++ struct drm_vgem_gem_object *vgem_obj = to_vgem_bo(obj);
++
++ if (obj)
++ drm_gem_free_mmap_offset(obj);
++
++ drm_gem_object_release(obj);
++
++ if (vgem_obj->pages)
++ vgem_gem_put_pages(vgem_obj);
++
++ kfree(vgem_obj);
++}
++
++static int vgem_gem_get_pages(struct drm_vgem_gem_object *obj)
++{
++ struct address_space *mapping;
++ gfp_t gfpmask = __GFP_NORETRY | __GFP_NOWARN;
++ int num_pages, i, ret = 0;
++
++ num_pages = obj->base.size / PAGE_SIZE;
++
++ if (!obj->pages) {
++ obj->pages = drm_malloc_ab(num_pages, sizeof(struct page *));
++ if (obj->pages == NULL)
++ return -ENOMEM;
++ }
++
++ mapping = obj->base.filp->f_path.dentry->d_inode->i_mapping;
++ gfpmask |= mapping_gfp_mask(mapping);
++
++ if (WARN_ON(mapping == NULL))
++ return VM_FAULT_SIGBUS;
++
++ for (i = 0; i < num_pages; i++) {
++ struct page *page;
++ page = shmem_read_mapping_page_gfp(mapping, i, gfpmask);
++ if (IS_ERR(page)) {
++ ret = PTR_ERR(page);
++ goto err_out;
++ }
++ obj->pages[i] = page;
++ }
++
++ return ret;
++
++err_out:
++ while (i--)
++ page_cache_release(obj->pages[i]);
++ drm_free_large(obj->pages);
++ obj->pages = NULL;
++ return ret;
++}
++
++static int vgem_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
++{
++ struct drm_vgem_gem_object *obj = to_vgem_bo(vma->vm_private_data);
++ loff_t num_pages;
++ pgoff_t page_offset;
++ int ret;
++
++ /* We don't use vmf->pgoff since that has the fake offset */
++ page_offset = ((unsigned long)vmf->virtual_address - vma->vm_start) >>
++ PAGE_SHIFT;
++
++ num_pages = obj->base.size / PAGE_SIZE;
++
++ if (WARN_ON(page_offset > num_pages))
++ return VM_FAULT_SIGBUS;
++
++ ret = vgem_gem_get_pages(obj);
++ if (ret)
++ return ret;
++
++ ret = vm_insert_page(vma, (unsigned long)vmf->virtual_address,
++ obj->pages[page_offset]);
++
++ /* Pretty dumb handler for now */
++ switch (ret) {
++ case 0:
++ case -ERESTARTSYS:
++ case -EINTR:
++ return VM_FAULT_NOPAGE;
++ default:
++ return VM_FAULT_SIGBUS;
++ }
++}
++
++static const struct vm_operations_struct vgem_gem_vm_ops = {
++ .fault = vgem_gem_fault,
++ .open = drm_gem_vm_open,
++ .close = drm_gem_vm_close,
++};
++
++/* ioctls */
++
++static struct drm_gem_object *vgem_gem_create(struct drm_device *dev,
++ struct drm_file *file,
++ unsigned int *handle,
++ unsigned long size)
++{
++ struct drm_vgem_gem_object *obj;
++ struct drm_gem_object *gem_object;
++ int err;
++
++ size = roundup(size, PAGE_SIZE);
++
++ obj = kzalloc(sizeof(*obj), GFP_KERNEL);
++ if (!obj)
++ return ERR_PTR(-ENOMEM);
++
++ gem_object = &obj->base;
++
++ if ((err = drm_gem_object_init(dev, gem_object, size)))
++ goto out;
++
++ if ((err = drm_gem_create_mmap_offset(gem_object)))
++ goto mmap_out;
++
++ if ((err = drm_gem_handle_create(file, gem_object, handle)))
++ goto handle_out;
++
++ drm_gem_object_unreference_unlocked(gem_object);
++
++ return gem_object;
++
++handle_out:
++ drm_gem_free_mmap_offset(gem_object);
++
++mmap_out:
++ drm_gem_object_release(gem_object);
++
++out:
++ kfree(gem_object);
++
++ return ERR_PTR(err);
++}
++
++static int vgem_gem_create_ioctl(struct drm_device *dev, void *data,
++ struct drm_file *file)
++{
++ struct vgem_gem_create *args = data;
++ struct drm_gem_object *gem_object;
++
++ gem_object = vgem_gem_create(dev, file, &args->handle, args->size);
++
++ if (IS_ERR(gem_object))
++ return PTR_ERR(gem_object);
++
++ return 0;
++}
++
++static int vgem_gem_mmap_ioctl(struct drm_device *dev, void *data,
++ struct drm_file *file)
++{
++ struct vgem_gem_mmap *args = data;
++ struct drm_gem_object *obj;
++
++ obj = drm_gem_object_lookup(dev, file, args->handle);
++ if (!obj)
++ return -ENOENT;
++
++ obj->filp->private_data = obj;
++
++ BUG_ON(!obj->map_list.map);
++
++ args->mapped = (uint64_t)obj->map_list.hash.key << PAGE_SHIFT;
++
++ drm_gem_object_unreference_unlocked(obj);
++
++ return 0;
++}
++
++static int vgem_gem_getparam_ioctl(struct drm_device *dev, void *data,
++ struct drm_file *file)
++{
++ struct vgem_gem_getparam *args = data;
++ int value=0, ret;
++
++ switch (args->param) {
++ case VGEM_PARAM_IS_VGEM:
++ value = 1;
++ }
++
++ ret = copy_to_user(args->value, &value, sizeof(int));
++ if (ret)
++ return ret;
++
++ return 0;
++}
++
++
++static struct drm_ioctl_desc vgem_ioctls[] = {
++ DRM_IOCTL_DEF_DRV(VGEM_GEM_CREATE, vgem_gem_create_ioctl,
++ DRM_UNLOCKED | DRM_AUTH),
++ DRM_IOCTL_DEF_DRV(VGEM_GEM_MMAP, vgem_gem_mmap_ioctl,
++ DRM_UNLOCKED | DRM_AUTH),
++ DRM_IOCTL_DEF_DRV(VGEM_GEM_GETPARAM, vgem_gem_getparam_ioctl,
++ DRM_UNLOCKED),
++};
++
++static const struct file_operations vgem_driver_fops = {
++ .owner = THIS_MODULE,
++ .open = drm_open,
++ .mmap = drm_gem_mmap,
++ .poll = drm_poll,
++ .read = drm_read,
++ .unlocked_ioctl = drm_ioctl,
++ .release = drm_release,
++};
++
++static struct drm_driver vgem_driver = {
++ .driver_features = DRIVER_BUS_PLATFORM | DRIVER_GEM,
++ .load = vgem_load,
++ .unload = vgem_unload,
++ .preclose = vgem_preclose,
++ .lastclose = vgem_lastclose,
++ .gem_init_object = vgem_gem_init_object,
++ .gem_free_object = vgem_gem_free_object,
++ .gem_vm_ops = &vgem_gem_vm_ops,
++ .ioctls = vgem_ioctls,
++ .fops = &vgem_driver_fops,
++ .name = DRIVER_NAME,
++ .desc = DRIVER_DESC,
++ .date = DRIVER_DATE,
++ .major = DRIVER_MAJOR,
++ .minor = DRIVER_MINOR,
++};
++
++static int vgem_platform_probe(struct platform_device *pdev)
++{
++ vgem_driver.num_ioctls = DRM_ARRAY_SIZE(vgem_ioctls);
++
++ return drm_platform_init(&vgem_driver, pdev);
++}
++
++static int vgem_platform_remove(struct platform_device *pdev)
++{
++ drm_platform_exit(&vgem_driver, pdev);
++
++ return 0;
++}
++
++static struct platform_driver vgem_platform_driver = {
++ .probe = vgem_platform_probe,
++ .remove = __devexit_p(vgem_platform_remove),
++ .driver = {
++ .owner = THIS_MODULE,
++ .name = DRIVER_NAME,
++ },
++};
++
++static struct platform_device *vgem_device;
++
++static int __init vgem_init(void)
++{
++ int ret;
++
++ if ((ret = platform_driver_register(&vgem_platform_driver)))
++ return ret;
++
++ vgem_device = platform_device_alloc("vgem", -1);
++ if (!vgem_device) {
++ ret = -ENOMEM;
++ goto out;
++ }
++
++ ret = platform_device_add(vgem_device);
++ if (!ret)
++ return 0;
++
++out:
++ platform_device_put(vgem_device);
++ platform_driver_unregister(&vgem_platform_driver);
++
++ return ret;
++}
++
++static void __exit vgem_exit(void)
++{
++ platform_device_unregister(vgem_device);
++ platform_driver_unregister(&vgem_platform_driver);
++}
++
++module_init(vgem_init);
++module_exit(vgem_exit);
++
++MODULE_AUTHOR("Red Hat, Inc.");
++MODULE_DESCRIPTION(DRIVER_DESC);
++MODULE_LICENSE("GPL and additional rights");
+diff --git a/include/drm/vgem_drm.h b/include/drm/vgem_drm.h
+new file mode 100644
+index 0000000..df83503
+--- /dev/null
++++ b/include/drm/vgem_drm.h
+@@ -0,0 +1,62 @@
++/*
++ * Copyright 2011 Red Hat, Inc.
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the "Software")
++ * to deal in the software without restriction, including without limitation
++ * on the rights to use, copy, modify, merge, publish, distribute, sub
++ * license, and/or sell copies of the Software, and to permit persons to whom
++ * them Software is furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice (including the next
++ * paragraph) shall be included in all copies or substantial portions of the
++ * Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTIBILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
++ * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY, WHETHER
++ * IN AN ACTION OF CONTRACT, TORT, OR OTHERWISE, ARISING FROM, OUT OF OR IN
++ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
++ */
++
++#ifndef VGEM_DRM_H
++#define VGEM_DRM_H
++
++/* Bare API largely ripped off from exynos driver */
++
++struct vgem_gem_create {
++ unsigned int size;
++ unsigned int flags;
++ unsigned int handle;
++};
++
++struct vgem_gem_mmap {
++ unsigned int handle;
++ unsigned int size;
++ uint64_t mapped;
++};
++
++struct vgem_gem_getparam {
++#define VGEM_PARAM_IS_VGEM 1
++ unsigned int param;
++ unsigned int *value;
++};
++
++#define DRM_VGEM_GEM_CREATE 0x00
++#define DRM_VGEM_GEM_MMAP 0x01
++#define DRM_VGEM_GEM_GETPARAM 0x02
++
++#define DRM_IOCTL_VGEM_GEM_CREATE \
++ DRM_IOWR(DRM_COMMAND_BASE + DRM_VGEM_GEM_CREATE, \
++ struct vgem_gem_create)
++
++#define DRM_IOCTL_VGEM_GEM_MMAP \
++ DRM_IOWR(DRM_COMMAND_BASE + DRM_VGEM_GEM_MMAP, \
++ struct vgem_gem_mmap)
++
++#define DRM_IOCTL_VGEM_GEM_GETPARAM \
++ DRM_IOWR(DRM_COMMAND_BASE + DRM_VGEM_GEM_GETPARAM, \
++ struct vgem_gem_getparam)
++
++#endif