aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/drm_gem.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/drm_gem.c')
-rw-r--r--drivers/gpu/drm/drm_gem.c109
1 files changed, 109 insertions, 0 deletions
diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c
index ccd1afdede02..b3939de6affd 100644
--- a/drivers/gpu/drm/drm_gem.c
+++ b/drivers/gpu/drm/drm_gem.c
@@ -64,6 +64,13 @@
64 * up at a later date, and as our interface with shmfs for memory allocation. 64 * up at a later date, and as our interface with shmfs for memory allocation.
65 */ 65 */
66 66
67/*
68 * We make up offsets for buffer objects so we can recognize them at
69 * mmap time.
70 */
71#define DRM_FILE_PAGE_OFFSET_START ((0xFFFFFFFFUL >> PAGE_SHIFT) + 1)
72#define DRM_FILE_PAGE_OFFSET_SIZE ((0xFFFFFFFFUL >> PAGE_SHIFT) * 16)
73
67/** 74/**
68 * Initialize the GEM device fields 75 * Initialize the GEM device fields
69 */ 76 */
@@ -71,6 +78,8 @@
71int 78int
72drm_gem_init(struct drm_device *dev) 79drm_gem_init(struct drm_device *dev)
73{ 80{
81 struct drm_gem_mm *mm;
82
74 spin_lock_init(&dev->object_name_lock); 83 spin_lock_init(&dev->object_name_lock);
75 idr_init(&dev->object_name_idr); 84 idr_init(&dev->object_name_idr);
76 atomic_set(&dev->object_count, 0); 85 atomic_set(&dev->object_count, 0);
@@ -79,9 +88,41 @@ drm_gem_init(struct drm_device *dev)
79 atomic_set(&dev->pin_memory, 0); 88 atomic_set(&dev->pin_memory, 0);
80 atomic_set(&dev->gtt_count, 0); 89 atomic_set(&dev->gtt_count, 0);
81 atomic_set(&dev->gtt_memory, 0); 90 atomic_set(&dev->gtt_memory, 0);
91
92 mm = drm_calloc(1, sizeof(struct drm_gem_mm), DRM_MEM_MM);
93 if (!mm) {
94 DRM_ERROR("out of memory\n");
95 return -ENOMEM;
96 }
97
98 dev->mm_private = mm;
99
100 if (drm_ht_create(&mm->offset_hash, 19)) {
101 drm_free(mm, sizeof(struct drm_gem_mm), DRM_MEM_MM);
102 return -ENOMEM;
103 }
104
105 if (drm_mm_init(&mm->offset_manager, DRM_FILE_PAGE_OFFSET_START,
106 DRM_FILE_PAGE_OFFSET_SIZE)) {
107 drm_free(mm, sizeof(struct drm_gem_mm), DRM_MEM_MM);
108 drm_ht_remove(&mm->offset_hash);
109 return -ENOMEM;
110 }
111
82 return 0; 112 return 0;
83} 113}
84 114
115void
116drm_gem_destroy(struct drm_device *dev)
117{
118 struct drm_gem_mm *mm = dev->mm_private;
119
120 drm_mm_takedown(&mm->offset_manager);
121 drm_ht_remove(&mm->offset_hash);
122 drm_free(mm, sizeof(struct drm_gem_mm), DRM_MEM_MM);
123 dev->mm_private = NULL;
124}
125
85/** 126/**
86 * Allocate a GEM object of the specified size with shmfs backing store 127 * Allocate a GEM object of the specified size with shmfs backing store
87 */ 128 */
@@ -419,3 +460,71 @@ drm_gem_object_handle_free(struct kref *kref)
419} 460}
420EXPORT_SYMBOL(drm_gem_object_handle_free); 461EXPORT_SYMBOL(drm_gem_object_handle_free);
421 462
463/**
464 * drm_gem_mmap - memory map routine for GEM objects
465 * @filp: DRM file pointer
466 * @vma: VMA for the area to be mapped
467 *
468 * If a driver supports GEM object mapping, mmap calls on the DRM file
469 * descriptor will end up here.
470 *
471 * If we find the object based on the offset passed in (vma->vm_pgoff will
472 * contain the fake offset we created when the GTT map ioctl was called on
473 * the object), we set up the driver fault handler so that any accesses
474 * to the object can be trapped, to perform migration, GTT binding, surface
475 * register allocation, or performance monitoring.
476 */
477int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)
478{
479 struct drm_file *priv = filp->private_data;
480 struct drm_device *dev = priv->minor->dev;
481 struct drm_gem_mm *mm = dev->mm_private;
482 struct drm_map *map = NULL;
483 struct drm_gem_object *obj;
484 struct drm_hash_item *hash;
485 unsigned long prot;
486 int ret = 0;
487
488 mutex_lock(&dev->struct_mutex);
489
490 if (drm_ht_find_item(&mm->offset_hash, vma->vm_pgoff, &hash)) {
491 mutex_unlock(&dev->struct_mutex);
492 return drm_mmap(filp, vma);
493 }
494
495 map = drm_hash_entry(hash, struct drm_map_list, hash)->map;
496 if (!map ||
497 ((map->flags & _DRM_RESTRICTED) && !capable(CAP_SYS_ADMIN))) {
498 ret = -EPERM;
499 goto out_unlock;
500 }
501
502 /* Check for valid size. */
503 if (map->size < vma->vm_end - vma->vm_start) {
504 ret = -EINVAL;
505 goto out_unlock;
506 }
507
508 obj = map->handle;
509 if (!obj->dev->driver->gem_vm_ops) {
510 ret = -EINVAL;
511 goto out_unlock;
512 }
513
514 vma->vm_flags |= VM_RESERVED | VM_IO | VM_PFNMAP | VM_DONTEXPAND;
515 vma->vm_ops = obj->dev->driver->gem_vm_ops;
516 vma->vm_private_data = map->handle;
517 /* FIXME: use pgprot_writecombine when available */
518 prot = pgprot_val(vma->vm_page_prot);
519 prot |= _PAGE_CACHE_WC;
520 vma->vm_page_prot = __pgprot(prot);
521
522 vma->vm_file = filp; /* Needed for drm_vm_open() */
523 drm_vm_open_locked(vma);
524
525out_unlock:
526 mutex_unlock(&dev->struct_mutex);
527
528 return ret;
529}
530EXPORT_SYMBOL(drm_gem_mmap);