Last active
August 29, 2015 14:21
-
-
Save tiagovignatti/6ede3a8330131b3243c0 to your computer and use it in GitHub Desktop.
vgem stuff
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--- /media/git/drm-intel/drivers/gpu/drm/vgem/vgem_drv.c 2015-05-14 18:25:58.743234338 -0300 | |
+++ /media/chromiumos/src/third_party/kernel/v3.14/drivers/gpu/drm/vgem/vgem_drv.c 2015-04-16 21:04:40.173736984 -0300 | |
@@ -30,6 +30,7 @@ | |
* software renderer and the X server for efficient buffer sharing. | |
*/ | |
+#include "drmP.h" | |
#include <linux/module.h> | |
#include <linux/ramfs.h> | |
#include <linux/shmem_fs.h> | |
@@ -44,7 +45,16 @@ | |
void vgem_gem_put_pages(struct drm_vgem_gem_object *obj) | |
{ | |
- drm_gem_put_pages(&obj->base, obj->pages, false, false); | |
+ int num_pages = obj->base.size / PAGE_SIZE; | |
+ int i; | |
+ | |
+ for (i = 0; i < num_pages; i++) { | |
+ if (obj->pages[i] == NULL) | |
+ break; | |
+ page_cache_release(obj->pages[i]); | |
+ } | |
+ | |
+ drm_free_large(obj->pages); | |
obj->pages = NULL; | |
} | |
@@ -71,19 +81,37 @@ | |
int vgem_gem_get_pages(struct drm_vgem_gem_object *obj) | |
{ | |
- struct page **pages; | |
+ struct address_space *mapping; | |
+ gfp_t gfpmask = GFP_KERNEL; | |
+ int num_pages, i, ret = 0; | |
if (obj->pages || obj->use_dma_buf) | |
return 0; | |
- pages = drm_gem_get_pages(&obj->base); | |
- if (IS_ERR(pages)) { | |
- return PTR_ERR(pages); | |
+ num_pages = obj->base.size / PAGE_SIZE; | |
+ 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); | |
+ | |
+ for (i = 0; i < num_pages; i++) { | |
+ struct page *page; | |
+ obj->pages[i] = NULL; | |
+ page = shmem_read_mapping_page_gfp(mapping, i, gfpmask); | |
+ if (IS_ERR(page)) { | |
+ ret = PTR_ERR(page); | |
+ goto err_out; | |
+ } | |
+ obj->pages[i] = page; | |
} | |
- obj->pages = pages; | |
+ return ret; | |
- return 0; | |
+err_out: | |
+ vgem_gem_put_pages(obj); | |
+ return ret; | |
} | |
static int vgem_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) | |
@@ -174,9 +202,8 @@ | |
{ | |
struct drm_gem_object *gem_object; | |
uint64_t size; | |
- uint64_t pitch = args->width * DIV_ROUND_UP(args->bpp, 8); | |
- size = args->height * pitch; | |
+ size = args->height * args->width * DIV_ROUND_UP(args->bpp, 8); | |
if (size == 0) | |
return -EINVAL; | |
@@ -188,7 +215,7 @@ | |
} | |
args->size = gem_object->size; | |
- args->pitch = pitch; | |
+ args->pitch = args->width; | |
DRM_DEBUG_DRIVER("Created object of size %lld\n", size); | |
@@ -289,6 +316,8 @@ | |
static struct drm_ioctl_desc vgem_ioctls[] = { | |
+ DRM_IOCTL_DEF_DRV(VGEM_MODE_MAP_DUMB, drm_mode_mmap_dumb_ioctl, | |
+ DRM_CONTROL_ALLOW|DRM_UNLOCKED|DRM_RENDER_ALLOW), | |
}; | |
static const struct file_operations vgem_driver_fops = { | |
@@ -302,7 +331,8 @@ | |
}; | |
static struct drm_driver vgem_driver = { | |
- .driver_features = DRIVER_GEM | DRIVER_PRIME, | |
+ .driver_features = | |
+ DRIVER_GEM | DRIVER_PRIME | DRIVER_RENDER, | |
.gem_free_object = vgem_gem_free_object, | |
.gem_vm_ops = &vgem_gem_vm_ops, | |
.ioctls = vgem_ioctls, | |
@@ -325,35 +355,65 @@ | |
.minor = DRIVER_MINOR, | |
}; | |
-struct drm_device *vgem_device; | |
+static int vgem_platform_probe(struct platform_device *pdev) | |
+{ | |
+ vgem_driver.num_ioctls = ARRAY_SIZE(vgem_ioctls); | |
+ | |
+ return drm_platform_init(&vgem_driver, pdev); | |
+} | |
+ | |
+static int vgem_platform_remove(struct platform_device *pdev) | |
+{ | |
+ drm_put_dev(platform_get_drvdata(pdev)); | |
+ return 0; | |
+} | |
+ | |
+static struct platform_driver vgem_platform_driver = { | |
+ .probe = vgem_platform_probe, | |
+ .remove = vgem_platform_remove, | |
+ .driver = { | |
+ .owner = THIS_MODULE, | |
+ .name = DRIVER_NAME, | |
+ }, | |
+}; | |
+ | |
+static struct platform_device *vgem_device; | |
static int __init vgem_init(void) | |
{ | |
int ret; | |
- vgem_device = drm_dev_alloc(&vgem_driver, NULL); | |
+ ret = platform_driver_register(&vgem_platform_driver); | |
+ if (ret) | |
+ goto out; | |
+ | |
+ vgem_device = platform_device_alloc("vgem", -1); | |
if (!vgem_device) { | |
ret = -ENOMEM; | |
- goto out; | |
+ goto unregister_out; | |
} | |
- ret = drm_dev_register(vgem_device, 0); | |
+ vgem_device->dev.coherent_dma_mask = ~0ULL; | |
+ vgem_device->dev.dma_mask = &vgem_device->dev.coherent_dma_mask; | |
+ ret = platform_device_add(vgem_device); | |
if (ret) | |
- goto out_unref; | |
+ goto put_out; | |
return 0; | |
-out_unref: | |
- drm_dev_unref(vgem_device); | |
+put_out: | |
+ platform_device_put(vgem_device); | |
+unregister_out: | |
+ platform_driver_unregister(&vgem_platform_driver); | |
out: | |
return ret; | |
} | |
static void __exit vgem_exit(void) | |
{ | |
- drm_dev_unregister(vgem_device); | |
- drm_dev_unref(vgem_device); | |
+ platform_device_unregister(vgem_device); | |
+ platform_driver_unregister(&vgem_platform_driver); | |
} | |
module_init(vgem_init); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--- /media/git/drm-intel/drivers/gpu/drm/vgem/vgem_drv.c 2015-05-14 18:25:58.743234338 -0300 | |
+++ /media/chromiumos/src/third_party/kernel/v3.8/drivers/gpu/drm/vgem/vgem_drv.c 2015-04-16 21:05:39.470843601 -0300 | |
@@ -30,10 +30,11 @@ | |
* software renderer and the X server for efficient buffer sharing. | |
*/ | |
+#include "drmP.h" | |
+#include <linux/dma-buf.h> | |
#include <linux/module.h> | |
#include <linux/ramfs.h> | |
#include <linux/shmem_fs.h> | |
-#include <linux/dma-buf.h> | |
#include "vgem_drv.h" | |
#define DRIVER_NAME "vgem" | |
@@ -42,9 +43,46 @@ | |
#define DRIVER_MAJOR 1 | |
#define DRIVER_MINOR 0 | |
+static int vgem_load(struct drm_device *dev, unsigned long flags) | |
+{ | |
+ return 0; | |
+} | |
+ | |
+static int vgem_unload(struct drm_device *dev) | |
+{ | |
+ return 0; | |
+} | |
+ | |
+static int vgem_open(struct drm_device *dev, struct drm_file *file) | |
+{ | |
+ 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; | |
+} | |
+ | |
void vgem_gem_put_pages(struct drm_vgem_gem_object *obj) | |
{ | |
- drm_gem_put_pages(&obj->base, obj->pages, false, false); | |
+ int num_pages = obj->base.size / PAGE_SIZE; | |
+ int i; | |
+ | |
+ for (i = 0; i < num_pages; i++) { | |
+ if (obj->pages[i] == NULL) | |
+ break; | |
+ page_cache_release(obj->pages[i]); | |
+ } | |
+ | |
+ drm_free_large(obj->pages); | |
obj->pages = NULL; | |
} | |
@@ -52,9 +90,10 @@ | |
{ | |
struct drm_vgem_gem_object *vgem_obj = to_vgem_bo(obj); | |
- drm_gem_free_mmap_offset(obj); | |
+ if (obj->map_list.map) | |
+ drm_gem_free_mmap_offset(obj); | |
- if (vgem_obj->use_dma_buf && obj->dma_buf) { | |
+ if (obj->dma_buf) { | |
dma_buf_put(obj->dma_buf); | |
obj->dma_buf = NULL; | |
} | |
@@ -71,24 +110,42 @@ | |
int vgem_gem_get_pages(struct drm_vgem_gem_object *obj) | |
{ | |
- struct page **pages; | |
+ struct address_space *mapping; | |
+ gfp_t gfpmask = GFP_KERNEL; | |
+ int num_pages, i, ret = 0; | |
if (obj->pages || obj->use_dma_buf) | |
return 0; | |
- pages = drm_gem_get_pages(&obj->base); | |
- if (IS_ERR(pages)) { | |
- return PTR_ERR(pages); | |
+ num_pages = obj->base.size / PAGE_SIZE; | |
+ 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); | |
+ | |
+ for (i = 0; i < num_pages; i++) { | |
+ struct page *page; | |
+ obj->pages[i] = NULL; | |
+ page = shmem_read_mapping_page_gfp(mapping, i, gfpmask); | |
+ if (IS_ERR(page)) { | |
+ ret = PTR_ERR(page); | |
+ goto err_out; | |
+ } | |
+ obj->pages[i] = page; | |
} | |
- obj->pages = pages; | |
+ return ret; | |
- return 0; | |
+err_out: | |
+ vgem_gem_put_pages(obj); | |
+ return ret; | |
} | |
static int vgem_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) | |
{ | |
- struct drm_vgem_gem_object *obj = vma->vm_private_data; | |
+ struct drm_vgem_gem_object *obj = to_vgem_bo(vma->vm_private_data); | |
struct drm_device *dev = obj->base.dev; | |
loff_t num_pages; | |
pgoff_t page_offset; | |
@@ -174,9 +231,8 @@ | |
{ | |
struct drm_gem_object *gem_object; | |
uint64_t size; | |
- uint64_t pitch = args->width * DIV_ROUND_UP(args->bpp, 8); | |
- size = args->height * pitch; | |
+ size = args->height * args->width * DIV_ROUND_UP(args->bpp, 8); | |
if (size == 0) | |
return -EINVAL; | |
@@ -188,7 +244,7 @@ | |
} | |
args->size = gem_object->size; | |
- args->pitch = pitch; | |
+ args->pitch = args->width; | |
DRM_DEBUG_DRIVER("Created object of size %lld\n", size); | |
@@ -208,7 +264,7 @@ | |
goto unlock; | |
} | |
- if (!drm_vma_node_has_offset(&obj->vma_node)) { | |
+ if (!obj->map_list.map) { | |
ret = drm_gem_create_mmap_offset(obj); | |
if (ret) | |
goto unref; | |
@@ -218,11 +274,13 @@ | |
obj->filp->private_data = obj; | |
+ BUG_ON(!obj->map_list.map); | |
+ | |
ret = vgem_gem_get_pages(to_vgem_bo(obj)); | |
if (ret) | |
goto fail_get_pages; | |
- *offset = drm_vma_node_offset_addr(&obj->vma_node); | |
+ *offset = (uint64_t)obj->map_list.hash.key << PAGE_SHIFT; | |
goto unref; | |
@@ -235,30 +293,42 @@ | |
return ret; | |
} | |
+ | |
int vgem_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma) | |
{ | |
struct drm_file *priv = filp->private_data; | |
struct drm_device *dev = priv->minor->dev; | |
- struct drm_vma_offset_node *node; | |
+ struct drm_gem_mm *mm = dev->mm_private; | |
+ struct drm_local_map *map = NULL; | |
struct drm_gem_object *obj; | |
struct drm_vgem_gem_object *vgem_obj; | |
+ struct drm_hash_item *hash; | |
int ret = 0; | |
+ if (drm_device_is_unplugged(dev)) | |
+ return -ENODEV; | |
+ | |
mutex_lock(&dev->struct_mutex); | |
- node = drm_vma_offset_exact_lookup(dev->vma_offset_manager, | |
- vma->vm_pgoff, | |
- vma_pages(vma)); | |
- if (!node) { | |
- ret = -EINVAL; | |
- goto out_unlock; | |
- } else if (!drm_vma_node_is_allowed(node, filp)) { | |
- ret = -EACCES; | |
+ if (drm_ht_find_item(&mm->offset_hash, vma->vm_pgoff, &hash)) { | |
+ mutex_unlock(&dev->struct_mutex); | |
+ return drm_mmap(filp, vma); | |
+ } | |
+ | |
+ map = drm_hash_entry(hash, struct drm_map_list, hash)->map; | |
+ if (!map || | |
+ ((map->flags & _DRM_RESTRICTED) && !capable(CAP_SYS_ADMIN))) { | |
+ ret = -EPERM; | |
goto out_unlock; | |
} | |
- obj = container_of(node, struct drm_gem_object, vma_node); | |
+ /* Check for valid size. */ | |
+ if (map->size < vma->vm_end - vma->vm_start) { | |
+ ret = -EINVAL; | |
+ goto out_unlock; | |
+ } | |
+ obj = map->handle; | |
vgem_obj = to_vgem_bo(obj); | |
if (obj->dma_buf && vgem_obj->use_dma_buf) { | |
@@ -273,10 +343,17 @@ | |
vma->vm_flags |= VM_IO | VM_MIXEDMAP | VM_DONTEXPAND | VM_DONTDUMP; | |
vma->vm_ops = obj->dev->driver->gem_vm_ops; | |
- vma->vm_private_data = vgem_obj; | |
+ vma->vm_private_data = map->handle; | |
vma->vm_page_prot = | |
pgprot_writecombine(vm_get_page_prot(vma->vm_flags)); | |
+ /* Take a ref for this mapping of the object, so that the fault | |
+ * handler can dereference the mmap offset's pointer to the object. | |
+ * This reference is cleaned up by the corresponding vm_close | |
+ * (which should happen whether the vma was created by this call, or | |
+ * by a vm_open due to mremap or partial unmap or whatever). | |
+ */ | |
+ | |
mutex_unlock(&dev->struct_mutex); | |
drm_gem_vm_open(vma); | |
return ret; | |
@@ -289,6 +366,8 @@ | |
static struct drm_ioctl_desc vgem_ioctls[] = { | |
+ DRM_IOCTL_DEF_DRV(VGEM_MODE_MAP_DUMB, drm_mode_mmap_dumb_ioctl, | |
+ DRM_CONTROL_ALLOW|DRM_UNLOCKED|DRM_RENDER_ALLOW), | |
}; | |
static const struct file_operations vgem_driver_fops = { | |
@@ -302,22 +381,24 @@ | |
}; | |
static struct drm_driver vgem_driver = { | |
- .driver_features = DRIVER_GEM | DRIVER_PRIME, | |
- .gem_free_object = vgem_gem_free_object, | |
- .gem_vm_ops = &vgem_gem_vm_ops, | |
- .ioctls = vgem_ioctls, | |
- .fops = &vgem_driver_fops, | |
- .dumb_create = vgem_gem_dumb_create, | |
- .dumb_map_offset = vgem_gem_dumb_map, | |
- .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 = vgem_gem_prime_import, | |
- .gem_prime_pin = vgem_gem_prime_pin, | |
- .gem_prime_unpin = vgem_gem_prime_unpin, | |
- .gem_prime_get_sg_table = vgem_gem_prime_get_sg_table, | |
- .gem_prime_vmap = vgem_gem_prime_vmap, | |
- .gem_prime_vunmap = vgem_gem_prime_vunmap, | |
+ .driver_features = | |
+ DRIVER_BUS_PLATFORM | DRIVER_GEM | DRIVER_PRIME | DRIVER_RENDER, | |
+ .load = vgem_load, | |
+ .unload = vgem_unload, | |
+ .open = vgem_open, | |
+ .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, | |
+ .dumb_create = vgem_gem_dumb_create, | |
+ .dumb_map_offset = vgem_gem_dumb_map, | |
+ .prime_handle_to_fd = drm_gem_prime_handle_to_fd, | |
+ .prime_fd_to_handle = drm_gem_prime_fd_to_handle, | |
+ .gem_prime_export = vgem_gem_prime_export, | |
+ .gem_prime_import = vgem_gem_prime_import, | |
.name = DRIVER_NAME, | |
.desc = DRIVER_DESC, | |
.date = DRIVER_DATE, | |
@@ -325,35 +406,66 @@ | |
.minor = DRIVER_MINOR, | |
}; | |
-struct drm_device *vgem_device; | |
+static int vgem_platform_probe(struct platform_device *pdev) | |
+{ | |
+ vgem_driver.num_ioctls = 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 = vgem_platform_remove, | |
+ .driver = { | |
+ .owner = THIS_MODULE, | |
+ .name = DRIVER_NAME, | |
+ }, | |
+}; | |
+ | |
+static struct platform_device *vgem_device; | |
static int __init vgem_init(void) | |
{ | |
int ret; | |
- vgem_device = drm_dev_alloc(&vgem_driver, NULL); | |
+ ret = platform_driver_register(&vgem_platform_driver); | |
+ if (ret) | |
+ goto out; | |
+ | |
+ vgem_device = platform_device_alloc("vgem", -1); | |
if (!vgem_device) { | |
ret = -ENOMEM; | |
- goto out; | |
+ goto unregister_out; | |
} | |
- ret = drm_dev_register(vgem_device, 0); | |
+ vgem_device->dev.coherent_dma_mask = ~0ULL; | |
+ vgem_device->dev.dma_mask = &vgem_device->dev.coherent_dma_mask; | |
+ ret = platform_device_add(vgem_device); | |
if (ret) | |
- goto out_unref; | |
+ goto put_out; | |
return 0; | |
-out_unref: | |
- drm_dev_unref(vgem_device); | |
+put_out: | |
+ platform_device_put(vgem_device); | |
+unregister_out: | |
+ platform_driver_unregister(&vgem_platform_driver); | |
out: | |
return ret; | |
} | |
static void __exit vgem_exit(void) | |
{ | |
- drm_dev_unregister(vgem_device); | |
- drm_dev_unref(vgem_device); | |
+ platform_device_unregister(vgem_device); | |
+ platform_driver_unregister(&vgem_platform_driver); | |
} | |
module_init(vgem_init); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment