1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71#define DRM_FILE_PAGE_OFFSET_START ((0xFFFFFFFFUL >> PAGE_SHIFT) + 1)
72#define DRM_FILE_PAGE_OFFSET_SIZE ((0xFFFFFFFFUL >> PAGE_SHIFT) * 16)
73
74
75
76
77
78int
79drm_gem_init(struct drm_device *dev)
80{
81 struct drm_gem_mm *mm;
82
83 spin_lock_init(&dev->object_name_lock);
84 idr_init(&dev->object_name_idr);
85 atomic_set(&dev->object_count, 0);
86 atomic_set(&dev->object_memory, 0);
87 atomic_set(&dev->pin_count, 0);
88 atomic_set(&dev->pin_memory, 0);
89 atomic_set(&dev->gtt_count, 0);
90 atomic_set(&dev->gtt_memory, 0);
91
92 mm = kzalloc(sizeof(struct drm_gem_mm), GFP_KERNEL);
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 kfree(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_ht_remove(&mm->offset_hash);
108 kfree(mm);
109 return -ENOMEM;
110 }
111
112 return 0;
113}
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 kfree(mm);
123 dev->mm_private = NULL;
124}
125
126
127
128
129struct drm_gem_object *
130drm_gem_object_alloc(struct drm_device *dev, size_t size)
131{
132 struct drm_gem_object *obj;
133
134 BUG_ON((size & (PAGE_SIZE - 1)) != 0);
135
136 obj = kzalloc(sizeof(*obj), GFP_KERNEL);
137 if (!obj)
138 goto free;
139
140 obj->dev = dev;
141 obj->filp = shmem_file_setup("drm mm object", size, VM_NORESERVE);
142 if (IS_ERR(obj->filp))
143 goto free;
144
145
146
147
148
149 mapping_set_gfp_mask(obj->filp->f_path.dentry->d_inode->i_mapping,
150 GFP_HIGHUSER |
151 __GFP_COLD |
152 __GFP_FS |
153 __GFP_RECLAIMABLE |
154 __GFP_NORETRY |
155 __GFP_NOWARN |
156 __GFP_NOMEMALLOC);
157
158 kref_init(&obj->refcount);
159 kref_init(&obj->handlecount);
160 obj->size = size;
161 if (dev->driver->gem_init_object != NULL &&
162 dev->driver->gem_init_object(obj) != 0) {
163 goto fput;
164 }
165 atomic_inc(&dev->object_count);
166 atomic_add(obj->size, &dev->object_memory);
167 return obj;
168fput:
169 fput(obj->filp);
170free:
171 kfree(obj);
172 return NULL;
173}
174EXPORT_SYMBOL(drm_gem_object_alloc);
175
176
177
178
179static int
180drm_gem_handle_delete(struct drm_file *filp, u32 handle)
181{
182 struct drm_device *dev;
183 struct drm_gem_object *obj;
184
185
186
187
188
189
190
191
192
193
194 spin_lock(&filp->table_lock);
195
196
197 obj = idr_find(&filp->object_idr, handle);
198 if (obj == NULL) {
199 spin_unlock(&filp->table_lock);
200 return -EINVAL;
201 }
202 dev = obj->dev;
203
204
205 idr_remove(&filp->object_idr, handle);
206 spin_unlock(&filp->table_lock);
207
208 mutex_lock(&dev->struct_mutex);
209 drm_gem_object_handle_unreference(obj);
210 mutex_unlock(&dev->struct_mutex);
211
212 return 0;
213}
214
215
216
217
218
219
220int
221drm_gem_handle_create(struct drm_file *file_priv,
222 struct drm_gem_object *obj,
223 u32 *handlep)
224{
225 int ret;
226
227
228
229
230again:
231
232 if (idr_pre_get(&file_priv->object_idr, GFP_KERNEL) == 0)
233 return -ENOMEM;
234
235
236 spin_lock(&file_priv->table_lock);
237 ret = idr_get_new_above(&file_priv->object_idr, obj, 1, (int *)handlep);
238 spin_unlock(&file_priv->table_lock);
239 if (ret == -EAGAIN)
240 goto again;
241
242 if (ret != 0)
243 return ret;
244
245 drm_gem_object_handle_reference(obj);
246 return 0;
247}
248EXPORT_SYMBOL(drm_gem_handle_create);
249
250
251struct drm_gem_object *
252drm_gem_object_lookup(struct drm_device *dev, struct drm_file *filp,
253 u32 handle)
254{
255 struct drm_gem_object *obj;
256
257 spin_lock(&filp->table_lock);
258
259
260 obj = idr_find(&filp->object_idr, handle);
261 if (obj == NULL) {
262 spin_unlock(&filp->table_lock);
263 return NULL;
264 }
265
266 drm_gem_object_reference(obj);
267
268 spin_unlock(&filp->table_lock);
269
270 return obj;
271}
272EXPORT_SYMBOL(drm_gem_object_lookup);
273
274
275
276
277int
278drm_gem_close_ioctl(struct drm_device *dev, void *data,
279 struct drm_file *file_priv)
280{
281 struct drm_gem_close *args = data;
282 int ret;
283
284 if (!(dev->driver->driver_features & DRIVER_GEM))
285 return -ENODEV;
286
287 ret = drm_gem_handle_delete(file_priv, args->handle);
288
289 return ret;
290}
291
292
293
294
295
296
297
298int
299drm_gem_flink_ioctl(struct drm_device *dev, void *data,
300 struct drm_file *file_priv)
301{
302 struct drm_gem_flink *args = data;
303 struct drm_gem_object *obj;
304 int ret;
305
306 if (!(dev->driver->driver_features & DRIVER_GEM))
307 return -ENODEV;
308
309 obj = drm_gem_object_lookup(dev, file_priv, args->handle);
310 if (obj == NULL)
311 return -EBADF;
312
313again:
314 if (idr_pre_get(&dev->object_name_idr, GFP_KERNEL) == 0) {
315 ret = -ENOMEM;
316 goto err;
317 }
318
319 spin_lock(&dev->object_name_lock);
320 if (!obj->name) {
321 ret = idr_get_new_above(&dev->object_name_idr, obj, 1,
322 &obj->name);
323 args->name = (uint64_t) obj->name;
324 spin_unlock(&dev->object_name_lock);
325
326 if (ret == -EAGAIN)
327 goto again;
328
329 if (ret != 0)
330 goto err;
331
332
333 drm_gem_object_reference(obj);
334 } else {
335 args->name = (uint64_t) obj->name;
336 spin_unlock(&dev->object_name_lock);
337 ret = 0;
338 }
339
340err:
341 mutex_lock(&dev->struct_mutex);
342 drm_gem_object_unreference(obj);
343 mutex_unlock(&dev->struct_mutex);
344 return ret;
345}
346
347
348
349
350
351
352
353int
354drm_gem_open_ioctl(struct drm_device *dev, void *data,
355 struct drm_file *file_priv)
356{
357 struct drm_gem_open *args = data;
358 struct drm_gem_object *obj;
359 int ret;
360 u32 handle;
361
362 if (!(dev->driver->driver_features & DRIVER_GEM))
363 return -ENODEV;
364
365 spin_lock(&dev->object_name_lock);
366 obj = idr_find(&dev->object_name_idr, (int) args->name);
367 if (obj)
368 drm_gem_object_reference(obj);
369 spin_unlock(&dev->object_name_lock);
370 if (!obj)
371 return -ENOENT;
372
373 ret = drm_gem_handle_create(file_priv, obj, &handle);
374 mutex_lock(&dev->struct_mutex);
375 drm_gem_object_unreference(obj);
376 mutex_unlock(&dev->struct_mutex);
377 if (ret)
378 return ret;
379
380 args->handle = handle;
381 args->size = obj->size;
382
383 return 0;
384}
385
386
387
388
389
390void
391drm_gem_open(struct drm_device *dev, struct drm_file *file_private)
392{
393 idr_init(&file_private->object_idr);
394 spin_lock_init(&file_private->table_lock);
395}
396
397
398
399
400
401static int
402drm_gem_object_release_handle(int id, void *ptr, void *data)
403{
404 struct drm_gem_object *obj = ptr;
405
406 drm_gem_object_handle_unreference(obj);
407
408 return 0;
409}
410
411
412
413
414
415
416void
417drm_gem_release(struct drm_device *dev, struct drm_file *file_private)
418{
419 mutex_lock(&dev->struct_mutex);
420 idr_for_each(&file_private->object_idr,
421 &drm_gem_object_release_handle, NULL);
422
423 idr_destroy(&file_private->object_idr);
424 mutex_unlock(&dev->struct_mutex);
425}
426
427
428
429
430
431
432void
433drm_gem_object_free(struct kref *kref)
434{
435 struct drm_gem_object *obj = (struct drm_gem_object *) kref;
436 struct drm_device *dev = obj->dev;
437
438 BUG_ON(!mutex_is_locked(&dev->struct_mutex));
439
440 if (dev->driver->gem_free_object != NULL)
441 dev->driver->gem_free_object(obj);
442
443 fput(obj->filp);
444 atomic_dec(&dev->object_count);
445 atomic_sub(obj->size, &dev->object_memory);
446 kfree(obj);
447}
448EXPORT_SYMBOL(drm_gem_object_free);
449
450
451
452
453
454
455
456
457void
458drm_gem_object_handle_free(struct kref *kref)
459{
460 struct drm_gem_object *obj = container_of(kref,
461 struct drm_gem_object,
462 handlecount);
463 struct drm_device *dev = obj->dev;
464
465
466 spin_lock(&dev->object_name_lock);
467 if (obj->name) {
468 idr_remove(&dev->object_name_idr, obj->name);
469 obj->name = 0;
470 spin_unlock(&dev->object_name_lock);
471
472
473
474
475 drm_gem_object_unreference(obj);
476 } else
477 spin_unlock(&dev->object_name_lock);
478
479}
480EXPORT_SYMBOL(drm_gem_object_handle_free);
481
482void drm_gem_vm_open(struct vm_area_struct *vma)
483{
484 struct drm_gem_object *obj = vma->vm_private_data;
485
486 drm_gem_object_reference(obj);
487}
488EXPORT_SYMBOL(drm_gem_vm_open);
489
490void drm_gem_vm_close(struct vm_area_struct *vma)
491{
492 struct drm_gem_object *obj = vma->vm_private_data;
493 struct drm_device *dev = obj->dev;
494
495 mutex_lock(&dev->struct_mutex);
496 drm_gem_object_unreference(obj);
497 mutex_unlock(&dev->struct_mutex);
498}
499EXPORT_SYMBOL(drm_gem_vm_close);
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)
517{
518 struct drm_file *priv = filp->private_data;
519 struct drm_device *dev = priv->minor->dev;
520 struct drm_gem_mm *mm = dev->mm_private;
521 struct drm_local_map *map = NULL;
522 struct drm_gem_object *obj;
523 struct drm_hash_item *hash;
524 int ret = 0;
525
526 mutex_lock(&dev->struct_mutex);
527
528 if (drm_ht_find_item(&mm->offset_hash, vma->vm_pgoff, &hash)) {
529 mutex_unlock(&dev->struct_mutex);
530 return drm_mmap(filp, vma);
531 }
532
533 map = drm_hash_entry(hash, struct drm_map_list, hash)->map;
534 if (!map ||
535 ((map->flags & _DRM_RESTRICTED) && !capable(CAP_SYS_ADMIN))) {
536 ret = -EPERM;
537 goto out_unlock;
538 }
539
540
541 if (map->size < vma->vm_end - vma->vm_start) {
542 ret = -EINVAL;
543 goto out_unlock;
544 }
545
546 obj = map->handle;
547 if (!obj->dev->driver->gem_vm_ops) {
548 ret = -EINVAL;
549 goto out_unlock;
550 }
551
552 vma->vm_flags |= VM_RESERVED | VM_IO | VM_PFNMAP | VM_DONTEXPAND;
553 vma->vm_ops = obj->dev->driver->gem_vm_ops;
554 vma->vm_private_data = map->handle;
555 vma->vm_page_prot = pgprot_writecombine(vm_get_page_prot(vma->vm_flags));
556
557
558
559
560
561
562
563 drm_gem_object_reference(obj);
564
565 vma->vm_file = filp;
566 drm_vm_open_locked(vma);
567
568out_unlock:
569 mutex_unlock(&dev->struct_mutex);
570
571 return ret;
572}
573EXPORT_SYMBOL(drm_gem_mmap);
574