blob: cff7317d3830e5f8df8c58ef7c8e61cc37301ccc [file] [log] [blame]
Eric Anholt673a3942008-07-30 12:06:12 -07001/*
2 * Copyright © 2008 Intel Corporation
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 *
23 * Authors:
24 * Eric Anholt <eric@anholt.net>
25 *
26 */
27
28#include <linux/types.h>
29#include <linux/slab.h>
30#include <linux/mm.h>
31#include <linux/uaccess.h>
32#include <linux/fs.h>
33#include <linux/file.h>
34#include <linux/module.h>
35#include <linux/mman.h>
36#include <linux/pagemap.h>
37#include "drmP.h"
38
39/** @file drm_gem.c
40 *
41 * This file provides some of the base ioctls and library routines for
42 * the graphics memory manager implemented by each device driver.
43 *
44 * Because various devices have different requirements in terms of
45 * synchronization and migration strategies, implementing that is left up to
46 * the driver, and all that the general API provides should be generic --
47 * allocating objects, reading/writing data with the cpu, freeing objects.
48 * Even there, platform-dependent optimizations for reading/writing data with
49 * the CPU mean we'll likely hook those out to driver-specific calls. However,
50 * the DRI2 implementation wants to have at least allocate/mmap be generic.
51 *
52 * The goal was to have swap-backed object allocation managed through
53 * struct file. However, file descriptors as handles to a struct file have
54 * two major failings:
55 * - Process limits prevent more than 1024 or so being used at a time by
56 * default.
57 * - Inability to allocate high fds will aggravate the X Server's select()
58 * handling, and likely that of many GL client applications as well.
59 *
60 * This led to a plan of using our own integer IDs (called handles, following
61 * DRM terminology) to mimic fds, and implement the fd syscalls we need as
62 * ioctls. The objects themselves will still include the struct file so
63 * that we can transition to fds if the required kernel infrastructure shows
64 * up at a later date, and as our interface with shmfs for memory allocation.
65 */
66
Jesse Barnesa2c0a972008-11-05 10:31:53 -080067/*
68 * We make up offsets for buffer objects so we can recognize them at
69 * mmap time.
70 */
Jordan Crouse05269a32010-05-27 13:40:27 -060071
72/* pgoff in mmap is an unsigned long, so we need to make sure that
73 * the faked up offset will fit
74 */
75
76#if BITS_PER_LONG == 64
Jesse Barnesa2c0a972008-11-05 10:31:53 -080077#define DRM_FILE_PAGE_OFFSET_START ((0xFFFFFFFFUL >> PAGE_SHIFT) + 1)
78#define DRM_FILE_PAGE_OFFSET_SIZE ((0xFFFFFFFFUL >> PAGE_SHIFT) * 16)
Jordan Crouse05269a32010-05-27 13:40:27 -060079#else
80#define DRM_FILE_PAGE_OFFSET_START ((0xFFFFFFFUL >> PAGE_SHIFT) + 1)
81#define DRM_FILE_PAGE_OFFSET_SIZE ((0xFFFFFFFUL >> PAGE_SHIFT) * 16)
82#endif
Jesse Barnesa2c0a972008-11-05 10:31:53 -080083
Eric Anholt673a3942008-07-30 12:06:12 -070084/**
85 * Initialize the GEM device fields
86 */
87
88int
89drm_gem_init(struct drm_device *dev)
90{
Jesse Barnesa2c0a972008-11-05 10:31:53 -080091 struct drm_gem_mm *mm;
92
Eric Anholt673a3942008-07-30 12:06:12 -070093 spin_lock_init(&dev->object_name_lock);
94 idr_init(&dev->object_name_idr);
95 atomic_set(&dev->object_count, 0);
96 atomic_set(&dev->object_memory, 0);
97 atomic_set(&dev->pin_count, 0);
98 atomic_set(&dev->pin_memory, 0);
99 atomic_set(&dev->gtt_count, 0);
100 atomic_set(&dev->gtt_memory, 0);
Jesse Barnesa2c0a972008-11-05 10:31:53 -0800101
Eric Anholt9a298b22009-03-24 12:23:04 -0700102 mm = kzalloc(sizeof(struct drm_gem_mm), GFP_KERNEL);
Jesse Barnesa2c0a972008-11-05 10:31:53 -0800103 if (!mm) {
104 DRM_ERROR("out of memory\n");
105 return -ENOMEM;
106 }
107
108 dev->mm_private = mm;
109
110 if (drm_ht_create(&mm->offset_hash, 19)) {
Eric Anholt9a298b22009-03-24 12:23:04 -0700111 kfree(mm);
Jesse Barnesa2c0a972008-11-05 10:31:53 -0800112 return -ENOMEM;
113 }
114
115 if (drm_mm_init(&mm->offset_manager, DRM_FILE_PAGE_OFFSET_START,
116 DRM_FILE_PAGE_OFFSET_SIZE)) {
Jesse Barnesa2c0a972008-11-05 10:31:53 -0800117 drm_ht_remove(&mm->offset_hash);
Eric Anholt9a298b22009-03-24 12:23:04 -0700118 kfree(mm);
Jesse Barnesa2c0a972008-11-05 10:31:53 -0800119 return -ENOMEM;
120 }
121
Eric Anholt673a3942008-07-30 12:06:12 -0700122 return 0;
123}
124
Jesse Barnesa2c0a972008-11-05 10:31:53 -0800125void
126drm_gem_destroy(struct drm_device *dev)
127{
128 struct drm_gem_mm *mm = dev->mm_private;
129
130 drm_mm_takedown(&mm->offset_manager);
131 drm_ht_remove(&mm->offset_hash);
Eric Anholt9a298b22009-03-24 12:23:04 -0700132 kfree(mm);
Jesse Barnesa2c0a972008-11-05 10:31:53 -0800133 dev->mm_private = NULL;
134}
135
Eric Anholt673a3942008-07-30 12:06:12 -0700136/**
Daniel Vetter1d397042010-04-09 19:05:04 +0000137 * Initialize an already allocate GEM object of the specified size with
138 * shmfs backing store.
139 */
140int drm_gem_object_init(struct drm_device *dev,
141 struct drm_gem_object *obj, size_t size)
142{
143 BUG_ON((size & (PAGE_SIZE - 1)) != 0);
144
145 obj->dev = dev;
146 obj->filp = shmem_file_setup("drm mm object", size, VM_NORESERVE);
147 if (IS_ERR(obj->filp))
148 return -ENOMEM;
149
150 kref_init(&obj->refcount);
151 kref_init(&obj->handlecount);
152 obj->size = size;
153
154 atomic_inc(&dev->object_count);
155 atomic_add(obj->size, &dev->object_memory);
156
157 return 0;
158}
159EXPORT_SYMBOL(drm_gem_object_init);
160
161/**
Eric Anholt673a3942008-07-30 12:06:12 -0700162 * Allocate a GEM object of the specified size with shmfs backing store
163 */
164struct drm_gem_object *
165drm_gem_object_alloc(struct drm_device *dev, size_t size)
166{
167 struct drm_gem_object *obj;
168
Robert P. J. Dayb798b1f2009-06-10 12:43:49 -0700169 obj = kzalloc(sizeof(*obj), GFP_KERNEL);
Jiri Slaby845792d2009-07-13 23:20:21 +0200170 if (!obj)
171 goto free;
Eric Anholt673a3942008-07-30 12:06:12 -0700172
Daniel Vetter1d397042010-04-09 19:05:04 +0000173 if (drm_gem_object_init(dev, obj, size) != 0)
Jiri Slaby845792d2009-07-13 23:20:21 +0200174 goto free;
Eric Anholt673a3942008-07-30 12:06:12 -0700175
Eric Anholt673a3942008-07-30 12:06:12 -0700176 if (dev->driver->gem_init_object != NULL &&
177 dev->driver->gem_init_object(obj) != 0) {
Jiri Slaby845792d2009-07-13 23:20:21 +0200178 goto fput;
Eric Anholt673a3942008-07-30 12:06:12 -0700179 }
Eric Anholt673a3942008-07-30 12:06:12 -0700180 return obj;
Jiri Slaby845792d2009-07-13 23:20:21 +0200181fput:
Daniel Vetter1d397042010-04-09 19:05:04 +0000182 /* Object_init mangles the global counters - readjust them. */
183 atomic_dec(&dev->object_count);
184 atomic_sub(obj->size, &dev->object_memory);
Jiri Slaby845792d2009-07-13 23:20:21 +0200185 fput(obj->filp);
186free:
187 kfree(obj);
188 return NULL;
Eric Anholt673a3942008-07-30 12:06:12 -0700189}
190EXPORT_SYMBOL(drm_gem_object_alloc);
191
192/**
193 * Removes the mapping from handle to filp for this object.
194 */
195static int
Pekka Paalanena1a2d1d2009-08-23 12:40:55 +0300196drm_gem_handle_delete(struct drm_file *filp, u32 handle)
Eric Anholt673a3942008-07-30 12:06:12 -0700197{
198 struct drm_device *dev;
199 struct drm_gem_object *obj;
200
201 /* This is gross. The idr system doesn't let us try a delete and
202 * return an error code. It just spews if you fail at deleting.
203 * So, we have to grab a lock around finding the object and then
204 * doing the delete on it and dropping the refcount, or the user
205 * could race us to double-decrement the refcount and cause a
206 * use-after-free later. Given the frequency of our handle lookups,
207 * we may want to use ida for number allocation and a hash table
208 * for the pointers, anyway.
209 */
210 spin_lock(&filp->table_lock);
211
212 /* Check if we currently have a reference on the object */
213 obj = idr_find(&filp->object_idr, handle);
214 if (obj == NULL) {
215 spin_unlock(&filp->table_lock);
216 return -EINVAL;
217 }
218 dev = obj->dev;
219
220 /* Release reference and decrement refcount. */
221 idr_remove(&filp->object_idr, handle);
222 spin_unlock(&filp->table_lock);
223
Luca Barbieribc9025b2010-02-09 05:49:12 +0000224 drm_gem_object_handle_unreference_unlocked(obj);
Eric Anholt673a3942008-07-30 12:06:12 -0700225
226 return 0;
227}
228
229/**
230 * Create a handle for this object. This adds a handle reference
231 * to the object, which includes a regular reference count. Callers
232 * will likely want to dereference the object afterwards.
233 */
234int
235drm_gem_handle_create(struct drm_file *file_priv,
236 struct drm_gem_object *obj,
Pekka Paalanena1a2d1d2009-08-23 12:40:55 +0300237 u32 *handlep)
Eric Anholt673a3942008-07-30 12:06:12 -0700238{
239 int ret;
240
241 /*
242 * Get the user-visible handle using idr.
243 */
244again:
245 /* ensure there is space available to allocate a handle */
246 if (idr_pre_get(&file_priv->object_idr, GFP_KERNEL) == 0)
247 return -ENOMEM;
248
249 /* do the allocation under our spinlock */
250 spin_lock(&file_priv->table_lock);
Pekka Paalanena1a2d1d2009-08-23 12:40:55 +0300251 ret = idr_get_new_above(&file_priv->object_idr, obj, 1, (int *)handlep);
Eric Anholt673a3942008-07-30 12:06:12 -0700252 spin_unlock(&file_priv->table_lock);
253 if (ret == -EAGAIN)
254 goto again;
255
256 if (ret != 0)
257 return ret;
258
259 drm_gem_object_handle_reference(obj);
260 return 0;
261}
262EXPORT_SYMBOL(drm_gem_handle_create);
263
264/** Returns a reference to the object named by the handle. */
265struct drm_gem_object *
266drm_gem_object_lookup(struct drm_device *dev, struct drm_file *filp,
Pekka Paalanena1a2d1d2009-08-23 12:40:55 +0300267 u32 handle)
Eric Anholt673a3942008-07-30 12:06:12 -0700268{
269 struct drm_gem_object *obj;
270
271 spin_lock(&filp->table_lock);
272
273 /* Check if we currently have a reference on the object */
274 obj = idr_find(&filp->object_idr, handle);
275 if (obj == NULL) {
276 spin_unlock(&filp->table_lock);
277 return NULL;
278 }
279
280 drm_gem_object_reference(obj);
281
282 spin_unlock(&filp->table_lock);
283
284 return obj;
285}
286EXPORT_SYMBOL(drm_gem_object_lookup);
287
288/**
289 * Releases the handle to an mm object.
290 */
291int
292drm_gem_close_ioctl(struct drm_device *dev, void *data,
293 struct drm_file *file_priv)
294{
295 struct drm_gem_close *args = data;
296 int ret;
297
298 if (!(dev->driver->driver_features & DRIVER_GEM))
299 return -ENODEV;
300
301 ret = drm_gem_handle_delete(file_priv, args->handle);
302
303 return ret;
304}
305
306/**
307 * Create a global name for an object, returning the name.
308 *
309 * Note that the name does not hold a reference; when the object
310 * is freed, the name goes away.
311 */
312int
313drm_gem_flink_ioctl(struct drm_device *dev, void *data,
314 struct drm_file *file_priv)
315{
316 struct drm_gem_flink *args = data;
317 struct drm_gem_object *obj;
318 int ret;
319
320 if (!(dev->driver->driver_features & DRIVER_GEM))
321 return -ENODEV;
322
323 obj = drm_gem_object_lookup(dev, file_priv, args->handle);
324 if (obj == NULL)
Chris Wilsonbf79cb92010-08-04 14:19:46 +0100325 return -ENOENT;
Eric Anholt673a3942008-07-30 12:06:12 -0700326
327again:
Chris Wilson3e49c4f2009-02-09 11:31:41 +0000328 if (idr_pre_get(&dev->object_name_idr, GFP_KERNEL) == 0) {
329 ret = -ENOMEM;
330 goto err;
331 }
Eric Anholt673a3942008-07-30 12:06:12 -0700332
333 spin_lock(&dev->object_name_lock);
Chris Wilson8d59bae2009-02-11 14:26:28 +0000334 if (!obj->name) {
335 ret = idr_get_new_above(&dev->object_name_idr, obj, 1,
336 &obj->name);
337 args->name = (uint64_t) obj->name;
Eric Anholt673a3942008-07-30 12:06:12 -0700338 spin_unlock(&dev->object_name_lock);
Chris Wilson8d59bae2009-02-11 14:26:28 +0000339
340 if (ret == -EAGAIN)
341 goto again;
342
343 if (ret != 0)
344 goto err;
345
346 /* Allocate a reference for the name table. */
347 drm_gem_object_reference(obj);
348 } else {
349 args->name = (uint64_t) obj->name;
350 spin_unlock(&dev->object_name_lock);
351 ret = 0;
Eric Anholt673a3942008-07-30 12:06:12 -0700352 }
Chris Wilson3e49c4f2009-02-09 11:31:41 +0000353
354err:
Luca Barbieribc9025b2010-02-09 05:49:12 +0000355 drm_gem_object_unreference_unlocked(obj);
Chris Wilson3e49c4f2009-02-09 11:31:41 +0000356 return ret;
Eric Anholt673a3942008-07-30 12:06:12 -0700357}
358
359/**
360 * Open an object using the global name, returning a handle and the size.
361 *
362 * This handle (of course) holds a reference to the object, so the object
363 * will not go away until the handle is deleted.
364 */
365int
366drm_gem_open_ioctl(struct drm_device *dev, void *data,
367 struct drm_file *file_priv)
368{
369 struct drm_gem_open *args = data;
370 struct drm_gem_object *obj;
371 int ret;
Pekka Paalanena1a2d1d2009-08-23 12:40:55 +0300372 u32 handle;
Eric Anholt673a3942008-07-30 12:06:12 -0700373
374 if (!(dev->driver->driver_features & DRIVER_GEM))
375 return -ENODEV;
376
377 spin_lock(&dev->object_name_lock);
378 obj = idr_find(&dev->object_name_idr, (int) args->name);
379 if (obj)
380 drm_gem_object_reference(obj);
381 spin_unlock(&dev->object_name_lock);
382 if (!obj)
383 return -ENOENT;
384
385 ret = drm_gem_handle_create(file_priv, obj, &handle);
Luca Barbieribc9025b2010-02-09 05:49:12 +0000386 drm_gem_object_unreference_unlocked(obj);
Eric Anholt673a3942008-07-30 12:06:12 -0700387 if (ret)
388 return ret;
389
390 args->handle = handle;
391 args->size = obj->size;
392
393 return 0;
394}
395
396/**
397 * Called at device open time, sets up the structure for handling refcounting
398 * of mm objects.
399 */
400void
401drm_gem_open(struct drm_device *dev, struct drm_file *file_private)
402{
403 idr_init(&file_private->object_idr);
404 spin_lock_init(&file_private->table_lock);
405}
406
407/**
408 * Called at device close to release the file's
409 * handle references on objects.
410 */
411static int
412drm_gem_object_release_handle(int id, void *ptr, void *data)
413{
414 struct drm_gem_object *obj = ptr;
415
Luca Barbieribc9025b2010-02-09 05:49:12 +0000416 drm_gem_object_handle_unreference_unlocked(obj);
Eric Anholt673a3942008-07-30 12:06:12 -0700417
418 return 0;
419}
420
421/**
422 * Called at close time when the filp is going away.
423 *
424 * Releases any remaining references on objects by this filp.
425 */
426void
427drm_gem_release(struct drm_device *dev, struct drm_file *file_private)
428{
Eric Anholt673a3942008-07-30 12:06:12 -0700429 idr_for_each(&file_private->object_idr,
430 &drm_gem_object_release_handle, NULL);
431
Chris Wilsonddd3d062010-07-24 22:28:25 +0100432 idr_remove_all(&file_private->object_idr);
Eric Anholt673a3942008-07-30 12:06:12 -0700433 idr_destroy(&file_private->object_idr);
Eric Anholt673a3942008-07-30 12:06:12 -0700434}
435
Daniel Vetterfd632aa2010-04-09 19:05:05 +0000436void
437drm_gem_object_release(struct drm_gem_object *obj)
Luca Barbieric3ae90c2010-02-09 05:49:11 +0000438{
439 struct drm_device *dev = obj->dev;
440 fput(obj->filp);
441 atomic_dec(&dev->object_count);
442 atomic_sub(obj->size, &dev->object_memory);
Luca Barbieric3ae90c2010-02-09 05:49:11 +0000443}
Daniel Vetterfd632aa2010-04-09 19:05:05 +0000444EXPORT_SYMBOL(drm_gem_object_release);
Luca Barbieric3ae90c2010-02-09 05:49:11 +0000445
Eric Anholt673a3942008-07-30 12:06:12 -0700446/**
447 * Called after the last reference to the object has been lost.
Luca Barbieric3ae90c2010-02-09 05:49:11 +0000448 * Must be called holding struct_ mutex
Eric Anholt673a3942008-07-30 12:06:12 -0700449 *
450 * Frees the object
451 */
452void
453drm_gem_object_free(struct kref *kref)
454{
455 struct drm_gem_object *obj = (struct drm_gem_object *) kref;
456 struct drm_device *dev = obj->dev;
457
458 BUG_ON(!mutex_is_locked(&dev->struct_mutex));
459
460 if (dev->driver->gem_free_object != NULL)
461 dev->driver->gem_free_object(obj);
Eric Anholt673a3942008-07-30 12:06:12 -0700462}
463EXPORT_SYMBOL(drm_gem_object_free);
464
465/**
Luca Barbieric3ae90c2010-02-09 05:49:11 +0000466 * Called after the last reference to the object has been lost.
467 * Must be called without holding struct_mutex
468 *
469 * Frees the object
470 */
471void
472drm_gem_object_free_unlocked(struct kref *kref)
473{
474 struct drm_gem_object *obj = (struct drm_gem_object *) kref;
475 struct drm_device *dev = obj->dev;
476
Daniel Vetterfd2e7932010-08-23 22:53:33 +0200477 if (dev->driver->gem_free_object != NULL) {
Luca Barbieric3ae90c2010-02-09 05:49:11 +0000478 mutex_lock(&dev->struct_mutex);
479 dev->driver->gem_free_object(obj);
480 mutex_unlock(&dev->struct_mutex);
481 }
Luca Barbieric3ae90c2010-02-09 05:49:11 +0000482}
483EXPORT_SYMBOL(drm_gem_object_free_unlocked);
484
485static void drm_gem_object_ref_bug(struct kref *list_kref)
486{
487 BUG();
488}
489
490/**
Eric Anholt673a3942008-07-30 12:06:12 -0700491 * Called after the last handle to the object has been closed
492 *
493 * Removes any name for the object. Note that this must be
494 * called before drm_gem_object_free or we'll be touching
495 * freed memory
496 */
497void
498drm_gem_object_handle_free(struct kref *kref)
499{
500 struct drm_gem_object *obj = container_of(kref,
501 struct drm_gem_object,
502 handlecount);
503 struct drm_device *dev = obj->dev;
504
505 /* Remove any name for this object */
506 spin_lock(&dev->object_name_lock);
507 if (obj->name) {
508 idr_remove(&dev->object_name_idr, obj->name);
Chris Wilson8d59bae2009-02-11 14:26:28 +0000509 obj->name = 0;
Eric Anholt673a3942008-07-30 12:06:12 -0700510 spin_unlock(&dev->object_name_lock);
511 /*
512 * The object name held a reference to this object, drop
513 * that now.
Luca Barbieric3ae90c2010-02-09 05:49:11 +0000514 *
515 * This cannot be the last reference, since the handle holds one too.
Eric Anholt673a3942008-07-30 12:06:12 -0700516 */
Luca Barbieric3ae90c2010-02-09 05:49:11 +0000517 kref_put(&obj->refcount, drm_gem_object_ref_bug);
Eric Anholt673a3942008-07-30 12:06:12 -0700518 } else
519 spin_unlock(&dev->object_name_lock);
520
521}
522EXPORT_SYMBOL(drm_gem_object_handle_free);
523
Jesse Barnesab00b3e2009-02-11 14:01:46 -0800524void drm_gem_vm_open(struct vm_area_struct *vma)
525{
526 struct drm_gem_object *obj = vma->vm_private_data;
527
528 drm_gem_object_reference(obj);
529}
530EXPORT_SYMBOL(drm_gem_vm_open);
531
532void drm_gem_vm_close(struct vm_area_struct *vma)
533{
534 struct drm_gem_object *obj = vma->vm_private_data;
Jesse Barnesab00b3e2009-02-11 14:01:46 -0800535
Luca Barbieribc9025b2010-02-09 05:49:12 +0000536 drm_gem_object_unreference_unlocked(obj);
Jesse Barnesab00b3e2009-02-11 14:01:46 -0800537}
538EXPORT_SYMBOL(drm_gem_vm_close);
539
540
Jesse Barnesa2c0a972008-11-05 10:31:53 -0800541/**
542 * drm_gem_mmap - memory map routine for GEM objects
543 * @filp: DRM file pointer
544 * @vma: VMA for the area to be mapped
545 *
546 * If a driver supports GEM object mapping, mmap calls on the DRM file
547 * descriptor will end up here.
548 *
549 * If we find the object based on the offset passed in (vma->vm_pgoff will
550 * contain the fake offset we created when the GTT map ioctl was called on
551 * the object), we set up the driver fault handler so that any accesses
552 * to the object can be trapped, to perform migration, GTT binding, surface
553 * register allocation, or performance monitoring.
554 */
555int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)
556{
557 struct drm_file *priv = filp->private_data;
558 struct drm_device *dev = priv->minor->dev;
559 struct drm_gem_mm *mm = dev->mm_private;
Benjamin Herrenschmidtf77d3902009-02-02 16:55:46 +1100560 struct drm_local_map *map = NULL;
Jesse Barnesa2c0a972008-11-05 10:31:53 -0800561 struct drm_gem_object *obj;
562 struct drm_hash_item *hash;
Jesse Barnesa2c0a972008-11-05 10:31:53 -0800563 int ret = 0;
564
565 mutex_lock(&dev->struct_mutex);
566
567 if (drm_ht_find_item(&mm->offset_hash, vma->vm_pgoff, &hash)) {
568 mutex_unlock(&dev->struct_mutex);
569 return drm_mmap(filp, vma);
570 }
571
572 map = drm_hash_entry(hash, struct drm_map_list, hash)->map;
573 if (!map ||
574 ((map->flags & _DRM_RESTRICTED) && !capable(CAP_SYS_ADMIN))) {
575 ret = -EPERM;
576 goto out_unlock;
577 }
578
579 /* Check for valid size. */
580 if (map->size < vma->vm_end - vma->vm_start) {
581 ret = -EINVAL;
582 goto out_unlock;
583 }
584
585 obj = map->handle;
586 if (!obj->dev->driver->gem_vm_ops) {
587 ret = -EINVAL;
588 goto out_unlock;
589 }
590
591 vma->vm_flags |= VM_RESERVED | VM_IO | VM_PFNMAP | VM_DONTEXPAND;
592 vma->vm_ops = obj->dev->driver->gem_vm_ops;
593 vma->vm_private_data = map->handle;
Jeremy Fitzhardinge79cc3042009-11-17 14:08:54 -0800594 vma->vm_page_prot = pgprot_writecombine(vm_get_page_prot(vma->vm_flags));
Jesse Barnesa2c0a972008-11-05 10:31:53 -0800595
Jesse Barnesab00b3e2009-02-11 14:01:46 -0800596 /* Take a ref for this mapping of the object, so that the fault
597 * handler can dereference the mmap offset's pointer to the object.
598 * This reference is cleaned up by the corresponding vm_close
599 * (which should happen whether the vma was created by this call, or
600 * by a vm_open due to mremap or partial unmap or whatever).
601 */
602 drm_gem_object_reference(obj);
603
Jesse Barnesa2c0a972008-11-05 10:31:53 -0800604 vma->vm_file = filp; /* Needed for drm_vm_open() */
605 drm_vm_open_locked(vma);
606
607out_unlock:
608 mutex_unlock(&dev->struct_mutex);
609
610 return ret;
611}
612EXPORT_SYMBOL(drm_gem_mmap);