blob: 03f8c426a040ede26a146529f0e8fc5b4697c2cf [file] [log] [blame]
Michael Street8bacdd02012-01-05 14:55:01 -08001/* Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13/* Implements an interface between KGSL and the DRM subsystem. For now this
14 * is pretty simple, but it will take on more of the workload as time goes
15 * on
16 */
17#include "drmP.h"
18#include "drm.h"
19#include <linux/android_pmem.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070020
21#include "kgsl.h"
22#include "kgsl_device.h"
23#include "kgsl_drm.h"
24#include "kgsl_mmu.h"
25#include "kgsl_sharedmem.h"
26
27#define DRIVER_AUTHOR "Qualcomm"
28#define DRIVER_NAME "kgsl"
29#define DRIVER_DESC "KGSL DRM"
30#define DRIVER_DATE "20100127"
31
32#define DRIVER_MAJOR 2
33#define DRIVER_MINOR 1
34#define DRIVER_PATCHLEVEL 1
35
36#define DRM_KGSL_GEM_FLAG_MAPPED (1 << 0)
37
38#define ENTRY_EMPTY -1
39#define ENTRY_NEEDS_CLEANUP -2
40
Michael Street8bacdd02012-01-05 14:55:01 -080041#define DRM_KGSL_NOT_INITED -1
42#define DRM_KGSL_INITED 1
43
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070044#define DRM_KGSL_NUM_FENCE_ENTRIES (DRM_KGSL_HANDLE_WAIT_ENTRIES << 2)
45#define DRM_KGSL_HANDLE_WAIT_ENTRIES 5
46
47/* Returns true if the memory type is in PMEM */
48
49#ifdef CONFIG_KERNEL_PMEM_SMI_REGION
50#define TYPE_IS_PMEM(_t) \
51 (((_t & DRM_KGSL_GEM_TYPE_MEM_MASK) == DRM_KGSL_GEM_TYPE_EBI) || \
52 ((_t & DRM_KGSL_GEM_TYPE_MEM_MASK) == DRM_KGSL_GEM_TYPE_SMI) || \
53 ((_t) & DRM_KGSL_GEM_TYPE_PMEM))
54#else
55#define TYPE_IS_PMEM(_t) \
56 (((_t & DRM_KGSL_GEM_TYPE_MEM_MASK) == DRM_KGSL_GEM_TYPE_EBI) || \
57 ((_t) & (DRM_KGSL_GEM_TYPE_PMEM | DRM_KGSL_GEM_PMEM_EBI)))
58#endif
59
60/* Returns true if the memory type is regular */
61
62#define TYPE_IS_MEM(_t) \
63 (((_t & DRM_KGSL_GEM_TYPE_MEM_MASK) == DRM_KGSL_GEM_TYPE_KMEM) || \
64 ((_t & DRM_KGSL_GEM_TYPE_MEM_MASK) == DRM_KGSL_GEM_TYPE_KMEM_NOCACHE) || \
65 ((_t) & DRM_KGSL_GEM_TYPE_MEM))
66
67#define TYPE_IS_FD(_t) ((_t) & DRM_KGSL_GEM_TYPE_FD_MASK)
68
69/* Returns true if KMEM region is uncached */
70
71#define IS_MEM_UNCACHED(_t) \
72 ((_t == DRM_KGSL_GEM_TYPE_KMEM_NOCACHE) || \
73 (_t == DRM_KGSL_GEM_TYPE_KMEM) || \
74 (TYPE_IS_MEM(_t) && (_t & DRM_KGSL_GEM_CACHE_WCOMBINE)))
75
76struct drm_kgsl_gem_object_wait_list_entry {
77 struct list_head list;
78 int pid;
79 int in_use;
80 wait_queue_head_t process_wait_q;
81};
82
83struct drm_kgsl_gem_object_fence {
84 int32_t fence_id;
85 unsigned int num_buffers;
86 int ts_valid;
87 unsigned int timestamp;
88 int ts_device;
89 int lockpid;
90 struct list_head buffers_in_fence;
91};
92
93struct drm_kgsl_gem_object_fence_list_entry {
94 struct list_head list;
95 int in_use;
96 struct drm_gem_object *gem_obj;
97};
98
99static int32_t fence_id = 0x1;
100
101static struct drm_kgsl_gem_object_fence
102 gem_buf_fence[DRM_KGSL_NUM_FENCE_ENTRIES];
103
104struct drm_kgsl_gem_object {
105 struct drm_gem_object *obj;
106 uint32_t type;
107 struct kgsl_memdesc memdesc;
108 struct kgsl_pagetable *pagetable;
109 uint64_t mmap_offset;
110 int bufcount;
111 int flags;
112 struct list_head list;
113 int active;
114
115 struct {
116 uint32_t offset;
117 uint32_t gpuaddr;
118 } bufs[DRM_KGSL_GEM_MAX_BUFFERS];
119
120 int bound;
121 int lockpid;
122 /* Put these here to avoid allocing all the time */
123 struct drm_kgsl_gem_object_wait_list_entry
124 wait_entries[DRM_KGSL_HANDLE_WAIT_ENTRIES];
125 /* Each object can only appear in a single fence */
126 struct drm_kgsl_gem_object_fence_list_entry
127 fence_entries[DRM_KGSL_NUM_FENCE_ENTRIES];
128
129 struct list_head wait_list;
130};
131
Michael Street8bacdd02012-01-05 14:55:01 -0800132static int kgsl_drm_inited = DRM_KGSL_NOT_INITED;
133
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700134/* This is a global list of all the memory currently mapped in the MMU */
135static struct list_head kgsl_mem_list;
136
137static void kgsl_gem_mem_flush(struct kgsl_memdesc *memdesc, int type, int op)
138{
139 int cacheop = 0;
140
141 switch (op) {
142 case DRM_KGSL_GEM_CACHE_OP_TO_DEV:
143 if (type & (DRM_KGSL_GEM_CACHE_WBACK |
144 DRM_KGSL_GEM_CACHE_WBACKWA))
145 cacheop = KGSL_CACHE_OP_CLEAN;
146
147 break;
148
149 case DRM_KGSL_GEM_CACHE_OP_FROM_DEV:
150 if (type & (DRM_KGSL_GEM_CACHE_WBACK |
151 DRM_KGSL_GEM_CACHE_WBACKWA |
152 DRM_KGSL_GEM_CACHE_WTHROUGH))
153 cacheop = KGSL_CACHE_OP_INV;
154 }
155
156 kgsl_cache_range_op(memdesc, cacheop);
157}
158
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700159/* TODO:
160 * Add vsync wait */
161
162static int kgsl_drm_load(struct drm_device *dev, unsigned long flags)
163{
164 return 0;
165}
166
167static int kgsl_drm_unload(struct drm_device *dev)
168{
169 return 0;
170}
171
172struct kgsl_drm_device_priv {
173 struct kgsl_device *device[KGSL_DEVICE_MAX];
174 struct kgsl_device_private *devpriv[KGSL_DEVICE_MAX];
175};
176
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700177void kgsl_drm_preclose(struct drm_device *dev, struct drm_file *file_priv)
178{
179}
180
181static int kgsl_drm_suspend(struct drm_device *dev, pm_message_t state)
182{
183 return 0;
184}
185
186static int kgsl_drm_resume(struct drm_device *dev)
187{
188 return 0;
189}
190
191static void
192kgsl_gem_free_mmap_offset(struct drm_gem_object *obj)
193{
194 struct drm_device *dev = obj->dev;
195 struct drm_gem_mm *mm = dev->mm_private;
196 struct drm_kgsl_gem_object *priv = obj->driver_private;
197 struct drm_map_list *list;
198
199 list = &obj->map_list;
200 drm_ht_remove_item(&mm->offset_hash, &list->hash);
201 if (list->file_offset_node) {
202 drm_mm_put_block(list->file_offset_node);
203 list->file_offset_node = NULL;
204 }
205
206 kfree(list->map);
207 list->map = NULL;
208
209 priv->mmap_offset = 0;
210}
211
212static int
213kgsl_gem_memory_allocated(struct drm_gem_object *obj)
214{
215 struct drm_kgsl_gem_object *priv = obj->driver_private;
216 return priv->memdesc.size ? 1 : 0;
217}
218
219static int
220kgsl_gem_alloc_memory(struct drm_gem_object *obj)
221{
222 struct drm_kgsl_gem_object *priv = obj->driver_private;
223 int index;
Michael Street8bacdd02012-01-05 14:55:01 -0800224 int result = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700225
226 /* Return if the memory is already allocated */
227
228 if (kgsl_gem_memory_allocated(obj) || TYPE_IS_FD(priv->type))
229 return 0;
230
Michael Street8bacdd02012-01-05 14:55:01 -0800231 if (priv->pagetable == NULL) {
232 priv->pagetable = kgsl_mmu_getpagetable(KGSL_MMU_GLOBAL_PT);
233
234 if (priv->pagetable == NULL) {
235 DRM_ERROR("Unable to get the GPU MMU pagetable\n");
236 return -EINVAL;
237 }
238 }
239
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700240 if (TYPE_IS_PMEM(priv->type)) {
241 int type;
242
243 if (priv->type == DRM_KGSL_GEM_TYPE_EBI ||
Michael Street8bacdd02012-01-05 14:55:01 -0800244 priv->type & DRM_KGSL_GEM_PMEM_EBI) {
245 type = PMEM_MEMTYPE_EBI1;
246 result = kgsl_sharedmem_ebimem_user(
247 &priv->memdesc,
248 priv->pagetable,
249 obj->size * priv->bufcount,
250 0);
251 if (result) {
252 DRM_ERROR(
253 "Unable to allocate PMEM memory\n");
254 return result;
255 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700256 }
Michael Street8bacdd02012-01-05 14:55:01 -0800257 else
258 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700259
260 } else if (TYPE_IS_MEM(priv->type)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700261
Michael Street8bacdd02012-01-05 14:55:01 -0800262 if (priv->type == DRM_KGSL_GEM_TYPE_KMEM ||
263 priv->type & DRM_KGSL_GEM_CACHE_MASK)
264 list_add(&priv->list, &kgsl_mem_list);
265
266 result = kgsl_sharedmem_vmalloc_user(&priv->memdesc,
267 priv->pagetable,
268 obj->size * priv->bufcount, 0);
269
270 if (result != 0) {
271 DRM_ERROR(
272 "Unable to allocate Vmalloc user memory\n");
273 return result;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700274 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700275 } else
276 return -EINVAL;
277
Michael Street8bacdd02012-01-05 14:55:01 -0800278 for (index = 0; index < priv->bufcount; index++) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700279 priv->bufs[index].offset = index * obj->size;
Michael Street8bacdd02012-01-05 14:55:01 -0800280 priv->bufs[index].gpuaddr =
281 priv->memdesc.gpuaddr +
282 priv->bufs[index].offset;
283 }
284 priv->flags |= DRM_KGSL_GEM_FLAG_MAPPED;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700285
286 return 0;
287}
288
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700289static void
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700290kgsl_gem_free_memory(struct drm_gem_object *obj)
291{
292 struct drm_kgsl_gem_object *priv = obj->driver_private;
293
294 if (!kgsl_gem_memory_allocated(obj) || TYPE_IS_FD(priv->type))
295 return;
296
297 kgsl_gem_mem_flush(&priv->memdesc, priv->type,
298 DRM_KGSL_GEM_CACHE_OP_FROM_DEV);
299
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700300 kgsl_sharedmem_free(&priv->memdesc);
Michael Street8bacdd02012-01-05 14:55:01 -0800301
302 kgsl_mmu_putpagetable(priv->pagetable);
303 priv->pagetable = NULL;
304
305 if ((priv->type == DRM_KGSL_GEM_TYPE_KMEM) ||
306 (priv->type & DRM_KGSL_GEM_CACHE_MASK))
307 list_del(&priv->list);
308
309 priv->flags &= ~DRM_KGSL_GEM_FLAG_MAPPED;
310
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700311}
312
313int
314kgsl_gem_init_object(struct drm_gem_object *obj)
315{
316 struct drm_kgsl_gem_object *priv;
317 priv = kzalloc(sizeof(*priv), GFP_KERNEL);
318 if (priv == NULL) {
319 DRM_ERROR("Unable to create GEM object\n");
320 return -ENOMEM;
321 }
322
323 obj->driver_private = priv;
324 priv->obj = obj;
325
326 return 0;
327}
328
329void
330kgsl_gem_free_object(struct drm_gem_object *obj)
331{
332 kgsl_gem_free_memory(obj);
333 kgsl_gem_free_mmap_offset(obj);
334 drm_gem_object_release(obj);
335 kfree(obj->driver_private);
336}
337
338static int
339kgsl_gem_create_mmap_offset(struct drm_gem_object *obj)
340{
341 struct drm_device *dev = obj->dev;
342 struct drm_gem_mm *mm = dev->mm_private;
343 struct drm_kgsl_gem_object *priv = obj->driver_private;
344 struct drm_map_list *list;
345 int msize;
346
347 list = &obj->map_list;
348 list->map = kzalloc(sizeof(struct drm_map_list), GFP_KERNEL);
349 if (list->map == NULL) {
350 DRM_ERROR("Unable to allocate drm_map_list\n");
351 return -ENOMEM;
352 }
353
354 msize = obj->size * priv->bufcount;
355
356 list->map->type = _DRM_GEM;
357 list->map->size = msize;
358 list->map->handle = obj;
359
360 /* Allocate a mmap offset */
361 list->file_offset_node = drm_mm_search_free(&mm->offset_manager,
362 msize / PAGE_SIZE,
363 0, 0);
364
365 if (!list->file_offset_node) {
366 DRM_ERROR("Failed to allocate offset for %d\n", obj->name);
367 kfree(list->map);
368 return -ENOMEM;
369 }
370
371 list->file_offset_node = drm_mm_get_block(list->file_offset_node,
372 msize / PAGE_SIZE, 0);
373
374 if (!list->file_offset_node) {
375 DRM_ERROR("Unable to create the file_offset_node\n");
376 kfree(list->map);
377 return -ENOMEM;
378 }
379
380 list->hash.key = list->file_offset_node->start;
381 if (drm_ht_insert_item(&mm->offset_hash, &list->hash)) {
382 DRM_ERROR("Failed to add to map hash\n");
383 drm_mm_put_block(list->file_offset_node);
384 kfree(list->map);
385 return -ENOMEM;
386 }
387
388 priv->mmap_offset = ((uint64_t) list->hash.key) << PAGE_SHIFT;
389
390 return 0;
391}
392
393int
394kgsl_gem_obj_addr(int drm_fd, int handle, unsigned long *start,
395 unsigned long *len)
396{
397 struct file *filp;
398 struct drm_device *dev;
399 struct drm_file *file_priv;
400 struct drm_gem_object *obj;
401 struct drm_kgsl_gem_object *priv;
402 int ret = 0;
403
404 filp = fget(drm_fd);
405 if (unlikely(filp == NULL)) {
Michael Street8bacdd02012-01-05 14:55:01 -0800406 DRM_ERROR("Unable to get the DRM file descriptor\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700407 return -EINVAL;
408 }
409 file_priv = filp->private_data;
410 if (unlikely(file_priv == NULL)) {
411 DRM_ERROR("Unable to get the file private data\n");
412 fput(filp);
413 return -EINVAL;
414 }
415 dev = file_priv->minor->dev;
416 if (unlikely(dev == NULL)) {
417 DRM_ERROR("Unable to get the minor device\n");
418 fput(filp);
419 return -EINVAL;
420 }
421
422 obj = drm_gem_object_lookup(dev, file_priv, handle);
423 if (unlikely(obj == NULL)) {
424 DRM_ERROR("Invalid GEM handle %x\n", handle);
425 fput(filp);
426 return -EBADF;
427 }
428
429 mutex_lock(&dev->struct_mutex);
430 priv = obj->driver_private;
431
432 /* We can only use the MDP for PMEM regions */
433
434 if (TYPE_IS_PMEM(priv->type)) {
435 *start = priv->memdesc.physaddr +
436 priv->bufs[priv->active].offset;
437
438 *len = priv->memdesc.size;
439
440 kgsl_gem_mem_flush(&priv->memdesc,
441 priv->type, DRM_KGSL_GEM_CACHE_OP_TO_DEV);
442 } else {
443 *start = 0;
444 *len = 0;
445 ret = -EINVAL;
446 }
447
448 drm_gem_object_unreference(obj);
449 mutex_unlock(&dev->struct_mutex);
450
451 fput(filp);
452 return ret;
453}
454
455static int
456kgsl_gem_init_obj(struct drm_device *dev,
457 struct drm_file *file_priv,
458 struct drm_gem_object *obj,
459 int *handle)
460{
461 struct drm_kgsl_gem_object *priv;
462 int ret, i;
463
464 mutex_lock(&dev->struct_mutex);
465 priv = obj->driver_private;
466
467 memset(&priv->memdesc, 0, sizeof(priv->memdesc));
468 priv->bufcount = 1;
469 priv->active = 0;
470 priv->bound = 0;
471
472 /* To preserve backwards compatability, the default memory source
473 is EBI */
474
475 priv->type = DRM_KGSL_GEM_TYPE_PMEM | DRM_KGSL_GEM_PMEM_EBI;
476
477 ret = drm_gem_handle_create(file_priv, obj, handle);
478
Michael Street8bacdd02012-01-05 14:55:01 -0800479 drm_gem_object_unreference(obj);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700480 INIT_LIST_HEAD(&priv->wait_list);
481
482 for (i = 0; i < DRM_KGSL_HANDLE_WAIT_ENTRIES; i++) {
483 INIT_LIST_HEAD((struct list_head *) &priv->wait_entries[i]);
484 priv->wait_entries[i].pid = 0;
485 init_waitqueue_head(&priv->wait_entries[i].process_wait_q);
486 }
487
488 for (i = 0; i < DRM_KGSL_NUM_FENCE_ENTRIES; i++) {
489 INIT_LIST_HEAD((struct list_head *) &priv->fence_entries[i]);
490 priv->fence_entries[i].in_use = 0;
491 priv->fence_entries[i].gem_obj = obj;
492 }
493
494 mutex_unlock(&dev->struct_mutex);
495 return ret;
496}
497
498int
499kgsl_gem_create_ioctl(struct drm_device *dev, void *data,
500 struct drm_file *file_priv)
501{
502 struct drm_kgsl_gem_create *create = data;
503 struct drm_gem_object *obj;
504 int ret, handle;
505
506 /* Page align the size so we can allocate multiple buffers */
507 create->size = ALIGN(create->size, 4096);
508
509 obj = drm_gem_object_alloc(dev, create->size);
510
511 if (obj == NULL) {
512 DRM_ERROR("Unable to allocate the GEM object\n");
513 return -ENOMEM;
514 }
515
516 ret = kgsl_gem_init_obj(dev, file_priv, obj, &handle);
517 if (ret)
518 return ret;
519
520 create->handle = handle;
521 return 0;
522}
523
524int
525kgsl_gem_create_fd_ioctl(struct drm_device *dev, void *data,
526 struct drm_file *file_priv)
527{
528 struct drm_kgsl_gem_create_fd *args = data;
529 struct file *file;
530 dev_t rdev;
531 struct fb_info *info;
532 struct drm_gem_object *obj;
533 struct drm_kgsl_gem_object *priv;
534 int ret, put_needed, handle;
535
536 file = fget_light(args->fd, &put_needed);
537
538 if (file == NULL) {
539 DRM_ERROR("Unable to get the file object\n");
540 return -EBADF;
541 }
542
543 rdev = file->f_dentry->d_inode->i_rdev;
544
545 /* Only framebuffer objects are supported ATM */
546
547 if (MAJOR(rdev) != FB_MAJOR) {
548 DRM_ERROR("File descriptor is not a framebuffer\n");
549 ret = -EBADF;
550 goto error_fput;
551 }
552
553 info = registered_fb[MINOR(rdev)];
554
555 if (info == NULL) {
556 DRM_ERROR("Framebuffer minor %d is not registered\n",
557 MINOR(rdev));
558 ret = -EBADF;
559 goto error_fput;
560 }
561
562 obj = drm_gem_object_alloc(dev, info->fix.smem_len);
563
564 if (obj == NULL) {
565 DRM_ERROR("Unable to allocate GEM object\n");
566 ret = -ENOMEM;
567 goto error_fput;
568 }
569
570 ret = kgsl_gem_init_obj(dev, file_priv, obj, &handle);
571
572 if (ret)
573 goto error_fput;
574
575 mutex_lock(&dev->struct_mutex);
576
577 priv = obj->driver_private;
578 priv->memdesc.physaddr = info->fix.smem_start;
579 priv->type = DRM_KGSL_GEM_TYPE_FD_FBMEM;
580
581 mutex_unlock(&dev->struct_mutex);
582 args->handle = handle;
583
584error_fput:
585 fput_light(file, put_needed);
586
587 return ret;
588}
589
590int
591kgsl_gem_setmemtype_ioctl(struct drm_device *dev, void *data,
592 struct drm_file *file_priv)
593{
594 struct drm_kgsl_gem_memtype *args = data;
595 struct drm_gem_object *obj;
596 struct drm_kgsl_gem_object *priv;
597 int ret = 0;
598
599 obj = drm_gem_object_lookup(dev, file_priv, args->handle);
600
601 if (obj == NULL) {
602 DRM_ERROR("Invalid GEM handle %x\n", args->handle);
603 return -EBADF;
604 }
605
606 mutex_lock(&dev->struct_mutex);
607 priv = obj->driver_private;
608
609 if (TYPE_IS_FD(priv->type))
610 ret = -EINVAL;
611 else {
612 if (TYPE_IS_PMEM(args->type) || TYPE_IS_MEM(args->type))
613 priv->type = args->type;
614 else
615 ret = -EINVAL;
616 }
617
618 drm_gem_object_unreference(obj);
619 mutex_unlock(&dev->struct_mutex);
620
621 return ret;
622}
623
624int
625kgsl_gem_getmemtype_ioctl(struct drm_device *dev, void *data,
626 struct drm_file *file_priv)
627{
628 struct drm_kgsl_gem_memtype *args = data;
629 struct drm_gem_object *obj;
630 struct drm_kgsl_gem_object *priv;
631
632 obj = drm_gem_object_lookup(dev, file_priv, args->handle);
633
634 if (obj == NULL) {
635 DRM_ERROR("Invalid GEM handle %x\n", args->handle);
636 return -EBADF;
637 }
638
639 mutex_lock(&dev->struct_mutex);
640 priv = obj->driver_private;
641
642 args->type = priv->type;
643
644 drm_gem_object_unreference(obj);
645 mutex_unlock(&dev->struct_mutex);
646
647 return 0;
648}
649
650int
651kgsl_gem_unbind_gpu_ioctl(struct drm_device *dev, void *data,
652 struct drm_file *file_priv)
653{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700654 return 0;
655}
656
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700657int
658kgsl_gem_bind_gpu_ioctl(struct drm_device *dev, void *data,
659 struct drm_file *file_priv)
660{
Michael Street8bacdd02012-01-05 14:55:01 -0800661 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700662}
663
664/* Allocate the memory and prepare it for CPU mapping */
665
666int
667kgsl_gem_alloc_ioctl(struct drm_device *dev, void *data,
668 struct drm_file *file_priv)
669{
670 struct drm_kgsl_gem_alloc *args = data;
671 struct drm_gem_object *obj;
672 struct drm_kgsl_gem_object *priv;
673 int ret;
674
675 obj = drm_gem_object_lookup(dev, file_priv, args->handle);
676
677 if (obj == NULL) {
678 DRM_ERROR("Invalid GEM handle %x\n", args->handle);
679 return -EBADF;
680 }
681
682 mutex_lock(&dev->struct_mutex);
683 priv = obj->driver_private;
684
685 ret = kgsl_gem_alloc_memory(obj);
686
687 if (ret) {
688 DRM_ERROR("Unable to allocate object memory\n");
689 } else if (!priv->mmap_offset) {
690 ret = kgsl_gem_create_mmap_offset(obj);
691 if (ret)
692 DRM_ERROR("Unable to create a mmap offset\n");
693 }
694
695 args->offset = priv->mmap_offset;
696
697 drm_gem_object_unreference(obj);
698 mutex_unlock(&dev->struct_mutex);
699
700 return ret;
701}
702
703int
704kgsl_gem_mmap_ioctl(struct drm_device *dev, void *data,
705 struct drm_file *file_priv)
706{
707 struct drm_kgsl_gem_mmap *args = data;
708 struct drm_gem_object *obj;
709 unsigned long addr;
710
711 obj = drm_gem_object_lookup(dev, file_priv, args->handle);
712
713 if (obj == NULL) {
714 DRM_ERROR("Invalid GEM handle %x\n", args->handle);
715 return -EBADF;
716 }
717
718 down_write(&current->mm->mmap_sem);
719
720 addr = do_mmap(obj->filp, 0, args->size,
721 PROT_READ | PROT_WRITE, MAP_SHARED,
722 args->offset);
723
724 up_write(&current->mm->mmap_sem);
725
726 mutex_lock(&dev->struct_mutex);
727 drm_gem_object_unreference(obj);
728 mutex_unlock(&dev->struct_mutex);
729
730 if (IS_ERR((void *) addr))
731 return addr;
732
733 args->hostptr = (uint32_t) addr;
734 return 0;
735}
736
737/* This function is deprecated */
738
739int
740kgsl_gem_prep_ioctl(struct drm_device *dev, void *data,
741 struct drm_file *file_priv)
742{
743 struct drm_kgsl_gem_prep *args = data;
744 struct drm_gem_object *obj;
745 struct drm_kgsl_gem_object *priv;
746 int ret;
747
748 obj = drm_gem_object_lookup(dev, file_priv, args->handle);
749
750 if (obj == NULL) {
751 DRM_ERROR("Invalid GEM handle %x\n", args->handle);
752 return -EBADF;
753 }
754
755 mutex_lock(&dev->struct_mutex);
756 priv = obj->driver_private;
757
758 ret = kgsl_gem_alloc_memory(obj);
759 if (ret) {
760 DRM_ERROR("Unable to allocate object memory\n");
761 drm_gem_object_unreference(obj);
762 mutex_unlock(&dev->struct_mutex);
763 return ret;
764 }
765
766 if (priv->mmap_offset == 0) {
767 ret = kgsl_gem_create_mmap_offset(obj);
768 if (ret) {
769 drm_gem_object_unreference(obj);
770 mutex_unlock(&dev->struct_mutex);
771 return ret;
772 }
773 }
774
775 args->offset = priv->mmap_offset;
776 args->phys = priv->memdesc.physaddr;
777
778 drm_gem_object_unreference(obj);
779 mutex_unlock(&dev->struct_mutex);
780
781 return 0;
782}
783
784int
785kgsl_gem_get_bufinfo_ioctl(struct drm_device *dev, void *data,
786 struct drm_file *file_priv)
787{
788 struct drm_kgsl_gem_bufinfo *args = data;
789 struct drm_gem_object *obj;
790 struct drm_kgsl_gem_object *priv;
791 int ret = -EINVAL;
792 int index;
793
794 obj = drm_gem_object_lookup(dev, file_priv, args->handle);
795
796 if (obj == NULL) {
797 DRM_ERROR("Invalid GEM handle %x\n", args->handle);
798 return -EBADF;
799 }
800
801 mutex_lock(&dev->struct_mutex);
802 priv = obj->driver_private;
803
804 if (!kgsl_gem_memory_allocated(obj)) {
805 DRM_ERROR("Memory not allocated for this object\n");
806 goto out;
807 }
808
809 for (index = 0; index < priv->bufcount; index++) {
810 args->offset[index] = priv->bufs[index].offset;
811 args->gpuaddr[index] = priv->bufs[index].gpuaddr;
812 }
813
814 args->count = priv->bufcount;
815 args->active = priv->active;
816
817 ret = 0;
818
819out:
820 drm_gem_object_unreference(obj);
821 mutex_unlock(&dev->struct_mutex);
822
823 return ret;
824}
825
826int
827kgsl_gem_set_bufcount_ioctl(struct drm_device *dev, void *data,
828 struct drm_file *file_priv)
829{
830 struct drm_kgsl_gem_bufcount *args = data;
831 struct drm_gem_object *obj;
832 struct drm_kgsl_gem_object *priv;
833 int ret = -EINVAL;
834
835 if (args->bufcount < 1 || args->bufcount > DRM_KGSL_GEM_MAX_BUFFERS)
836 return -EINVAL;
837
838 obj = drm_gem_object_lookup(dev, file_priv, args->handle);
839
840 if (obj == NULL) {
841 DRM_ERROR("Invalid GEM handle %x\n", args->handle);
842 return -EBADF;
843 }
844
845 mutex_lock(&dev->struct_mutex);
846 priv = obj->driver_private;
847
848 /* It is too much math to worry about what happens if we are already
849 allocated, so just bail if we are */
850
851 if (kgsl_gem_memory_allocated(obj)) {
852 DRM_ERROR("Memory already allocated - cannot change"
853 "number of buffers\n");
854 goto out;
855 }
856
857 priv->bufcount = args->bufcount;
858 ret = 0;
859
860out:
861 drm_gem_object_unreference(obj);
862 mutex_unlock(&dev->struct_mutex);
863
864 return ret;
865}
866
867int
868kgsl_gem_set_active_ioctl(struct drm_device *dev, void *data,
869 struct drm_file *file_priv)
870{
871 struct drm_kgsl_gem_active *args = data;
872 struct drm_gem_object *obj;
873 struct drm_kgsl_gem_object *priv;
874 int ret = -EINVAL;
875
876 obj = drm_gem_object_lookup(dev, file_priv, args->handle);
877
878 if (obj == NULL) {
879 DRM_ERROR("Invalid GEM handle %x\n", args->handle);
880 return -EBADF;
881 }
882
883 mutex_lock(&dev->struct_mutex);
884 priv = obj->driver_private;
885
886 if (args->active < 0 || args->active >= priv->bufcount) {
887 DRM_ERROR("Invalid active buffer %d\n", args->active);
888 goto out;
889 }
890
891 priv->active = args->active;
892 ret = 0;
893
894out:
895 drm_gem_object_unreference(obj);
896 mutex_unlock(&dev->struct_mutex);
897
898 return ret;
899}
900
901int kgsl_gem_kmem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
902{
903 struct drm_gem_object *obj = vma->vm_private_data;
904 struct drm_device *dev = obj->dev;
905 struct drm_kgsl_gem_object *priv;
906 unsigned long offset, pg;
907 struct page *page;
908
909 mutex_lock(&dev->struct_mutex);
910
911 priv = obj->driver_private;
912
913 offset = (unsigned long) vmf->virtual_address - vma->vm_start;
914 pg = (unsigned long) priv->memdesc.hostptr + offset;
915
916 page = vmalloc_to_page((void *) pg);
917 if (!page) {
918 mutex_unlock(&dev->struct_mutex);
919 return VM_FAULT_SIGBUS;
920 }
921
922 get_page(page);
923 vmf->page = page;
924
925 mutex_unlock(&dev->struct_mutex);
926 return 0;
927}
928
929int kgsl_gem_phys_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
930{
931 struct drm_gem_object *obj = vma->vm_private_data;
932 struct drm_device *dev = obj->dev;
933 struct drm_kgsl_gem_object *priv;
934 unsigned long offset, pfn;
935 int ret = 0;
936
937 offset = ((unsigned long) vmf->virtual_address - vma->vm_start) >>
938 PAGE_SHIFT;
939
940 mutex_lock(&dev->struct_mutex);
941
942 priv = obj->driver_private;
943
944 pfn = (priv->memdesc.physaddr >> PAGE_SHIFT) + offset;
945 ret = vm_insert_pfn(vma,
946 (unsigned long) vmf->virtual_address, pfn);
947 mutex_unlock(&dev->struct_mutex);
948
949 switch (ret) {
950 case -ENOMEM:
951 case -EAGAIN:
952 return VM_FAULT_OOM;
953 case -EFAULT:
954 return VM_FAULT_SIGBUS;
955 default:
956 return VM_FAULT_NOPAGE;
957 }
958}
959
960static struct vm_operations_struct kgsl_gem_kmem_vm_ops = {
961 .fault = kgsl_gem_kmem_fault,
962 .open = drm_gem_vm_open,
963 .close = drm_gem_vm_close,
964};
965
966static struct vm_operations_struct kgsl_gem_phys_vm_ops = {
967 .fault = kgsl_gem_phys_fault,
968 .open = drm_gem_vm_open,
969 .close = drm_gem_vm_close,
970};
971
972/* This is a clone of the standard drm_gem_mmap function modified to allow
973 us to properly map KMEM regions as well as the PMEM regions */
974
975int msm_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)
976{
977 struct drm_file *priv = filp->private_data;
978 struct drm_device *dev = priv->minor->dev;
979 struct drm_gem_mm *mm = dev->mm_private;
980 struct drm_local_map *map = NULL;
981 struct drm_gem_object *obj;
982 struct drm_hash_item *hash;
983 struct drm_kgsl_gem_object *gpriv;
984 int ret = 0;
985
986 mutex_lock(&dev->struct_mutex);
987
988 if (drm_ht_find_item(&mm->offset_hash, vma->vm_pgoff, &hash)) {
989 mutex_unlock(&dev->struct_mutex);
990 return drm_mmap(filp, vma);
991 }
992
993 map = drm_hash_entry(hash, struct drm_map_list, hash)->map;
994 if (!map ||
995 ((map->flags & _DRM_RESTRICTED) && !capable(CAP_SYS_ADMIN))) {
996 ret = -EPERM;
997 goto out_unlock;
998 }
999
1000 /* Check for valid size. */
1001 if (map->size < vma->vm_end - vma->vm_start) {
1002 ret = -EINVAL;
1003 goto out_unlock;
1004 }
1005
1006 obj = map->handle;
1007
1008 gpriv = obj->driver_private;
1009
1010 /* VM_PFNMAP is only for memory that doesn't use struct page
1011 * in other words, not "normal" memory. If you try to use it
1012 * with "normal" memory then the mappings don't get flushed. */
1013
1014 if (TYPE_IS_MEM(gpriv->type)) {
1015 vma->vm_flags |= VM_RESERVED | VM_DONTEXPAND;
1016 vma->vm_ops = &kgsl_gem_kmem_vm_ops;
1017 } else {
1018 vma->vm_flags |= VM_RESERVED | VM_IO | VM_PFNMAP |
1019 VM_DONTEXPAND;
1020 vma->vm_ops = &kgsl_gem_phys_vm_ops;
1021 }
1022
1023 vma->vm_private_data = map->handle;
1024
1025
1026 /* Take care of requested caching policy */
1027 if (gpriv->type == DRM_KGSL_GEM_TYPE_KMEM ||
1028 gpriv->type & DRM_KGSL_GEM_CACHE_MASK) {
1029 if (gpriv->type & DRM_KGSL_GEM_CACHE_WBACKWA)
1030 vma->vm_page_prot =
1031 pgprot_writebackwacache(vma->vm_page_prot);
1032 else if (gpriv->type & DRM_KGSL_GEM_CACHE_WBACK)
1033 vma->vm_page_prot =
1034 pgprot_writebackcache(vma->vm_page_prot);
1035 else if (gpriv->type & DRM_KGSL_GEM_CACHE_WTHROUGH)
1036 vma->vm_page_prot =
1037 pgprot_writethroughcache(vma->vm_page_prot);
1038 else
1039 vma->vm_page_prot =
1040 pgprot_writecombine(vma->vm_page_prot);
1041 } else {
1042 if (gpriv->type == DRM_KGSL_GEM_TYPE_KMEM_NOCACHE)
1043 vma->vm_page_prot =
1044 pgprot_noncached(vma->vm_page_prot);
1045 else
1046 /* default pmem is WC */
1047 vma->vm_page_prot =
1048 pgprot_writecombine(vma->vm_page_prot);
1049 }
1050
1051 /* flush out existing KMEM cached mappings if new ones are
1052 * of uncached type */
1053 if (IS_MEM_UNCACHED(gpriv->type))
1054 kgsl_cache_range_op(&gpriv->memdesc,
1055 KGSL_CACHE_OP_FLUSH);
1056
1057 /* Add the other memory types here */
1058
1059 /* Take a ref for this mapping of the object, so that the fault
1060 * handler can dereference the mmap offset's pointer to the object.
1061 * This reference is cleaned up by the corresponding vm_close
1062 * (which should happen whether the vma was created by this call, or
1063 * by a vm_open due to mremap or partial unmap or whatever).
1064 */
1065 drm_gem_object_reference(obj);
1066
1067 vma->vm_file = filp; /* Needed for drm_vm_open() */
1068 drm_vm_open_locked(vma);
1069
1070out_unlock:
1071 mutex_unlock(&dev->struct_mutex);
1072
1073 return ret;
1074}
1075
1076void
1077cleanup_fence(struct drm_kgsl_gem_object_fence *fence, int check_waiting)
1078{
1079 int j;
1080 struct drm_kgsl_gem_object_fence_list_entry *this_fence_entry = NULL;
1081 struct drm_kgsl_gem_object *unlock_obj;
1082 struct drm_gem_object *obj;
1083 struct drm_kgsl_gem_object_wait_list_entry *lock_next;
1084
1085 fence->ts_valid = 0;
1086 fence->timestamp = -1;
1087 fence->ts_device = -1;
1088
1089 /* Walk the list of buffers in this fence and clean up the */
1090 /* references. Note that this can cause memory allocations */
1091 /* to be freed */
1092 for (j = fence->num_buffers; j > 0; j--) {
1093 this_fence_entry =
1094 (struct drm_kgsl_gem_object_fence_list_entry *)
1095 fence->buffers_in_fence.prev;
1096
1097 this_fence_entry->in_use = 0;
1098 obj = this_fence_entry->gem_obj;
1099 unlock_obj = obj->driver_private;
1100
1101 /* Delete it from the list */
1102
1103 list_del(&this_fence_entry->list);
1104
1105 /* we are unlocking - see if there are other pids waiting */
1106 if (check_waiting) {
1107 if (!list_empty(&unlock_obj->wait_list)) {
1108 lock_next =
1109 (struct drm_kgsl_gem_object_wait_list_entry *)
1110 unlock_obj->wait_list.prev;
1111
1112 list_del((struct list_head *)&lock_next->list);
1113
1114 unlock_obj->lockpid = 0;
1115 wake_up_interruptible(
1116 &lock_next->process_wait_q);
1117 lock_next->pid = 0;
1118
1119 } else {
1120 /* List is empty so set pid to 0 */
1121 unlock_obj->lockpid = 0;
1122 }
1123 }
1124
1125 drm_gem_object_unreference(obj);
1126 }
1127 /* here all the buffers in the fence are released */
1128 /* clear the fence entry */
1129 fence->fence_id = ENTRY_EMPTY;
1130}
1131
1132int
1133find_empty_fence(void)
1134{
1135 int i;
1136
1137 for (i = 0; i < DRM_KGSL_NUM_FENCE_ENTRIES; i++) {
1138 if (gem_buf_fence[i].fence_id == ENTRY_EMPTY) {
1139 gem_buf_fence[i].fence_id = fence_id++;
1140 gem_buf_fence[i].ts_valid = 0;
1141 INIT_LIST_HEAD(&(gem_buf_fence[i].buffers_in_fence));
1142 if (fence_id == 0xFFFFFFF0)
1143 fence_id = 1;
1144 return i;
1145 } else {
1146
1147 /* Look for entries to be cleaned up */
1148 if (gem_buf_fence[i].fence_id == ENTRY_NEEDS_CLEANUP)
1149 cleanup_fence(&gem_buf_fence[i], 0);
1150 }
1151 }
1152
1153 return ENTRY_EMPTY;
1154}
1155
1156int
1157find_fence(int index)
1158{
1159 int i;
1160
1161 for (i = 0; i < DRM_KGSL_NUM_FENCE_ENTRIES; i++) {
1162 if (gem_buf_fence[i].fence_id == index)
1163 return i;
1164 }
1165
1166 return ENTRY_EMPTY;
1167}
1168
1169void
1170wakeup_fence_entries(struct drm_kgsl_gem_object_fence *fence)
1171{
1172 struct drm_kgsl_gem_object_fence_list_entry *this_fence_entry = NULL;
1173 struct drm_kgsl_gem_object_wait_list_entry *lock_next;
1174 struct drm_kgsl_gem_object *unlock_obj;
1175 struct drm_gem_object *obj;
1176
1177 /* TS has expired when we get here */
1178 fence->ts_valid = 0;
1179 fence->timestamp = -1;
1180 fence->ts_device = -1;
1181
1182 list_for_each_entry(this_fence_entry, &fence->buffers_in_fence, list) {
1183 obj = this_fence_entry->gem_obj;
1184 unlock_obj = obj->driver_private;
1185
1186 if (!list_empty(&unlock_obj->wait_list)) {
1187 lock_next =
1188 (struct drm_kgsl_gem_object_wait_list_entry *)
1189 unlock_obj->wait_list.prev;
1190
1191 /* Unblock the pid */
1192 lock_next->pid = 0;
1193
1194 /* Delete it from the list */
1195 list_del((struct list_head *)&lock_next->list);
1196
1197 unlock_obj->lockpid = 0;
1198 wake_up_interruptible(&lock_next->process_wait_q);
1199
1200 } else {
1201 /* List is empty so set pid to 0 */
1202 unlock_obj->lockpid = 0;
1203 }
1204 }
1205 fence->fence_id = ENTRY_NEEDS_CLEANUP; /* Mark it as needing cleanup */
1206}
1207
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001208int
1209kgsl_gem_lock_handle_ioctl(struct drm_device *dev, void *data,
1210 struct drm_file *file_priv)
1211{
1212 /* The purpose of this function is to lock a given set of handles. */
1213 /* The driver will maintain a list of locked handles. */
1214 /* If a request comes in for a handle that's locked the thread will */
1215 /* block until it's no longer in use. */
1216
1217 struct drm_kgsl_gem_lock_handles *args = data;
1218 struct drm_gem_object *obj;
1219 struct drm_kgsl_gem_object *priv;
1220 struct drm_kgsl_gem_object_fence_list_entry *this_fence_entry = NULL;
1221 struct drm_kgsl_gem_object_fence *fence;
1222 struct drm_kgsl_gem_object_wait_list_entry *lock_item;
1223 int i, j;
1224 int result = 0;
1225 uint32_t *lock_list;
1226 uint32_t *work_list = NULL;
1227 int32_t fence_index;
1228
1229 /* copy in the data from user space */
1230 lock_list = kzalloc(sizeof(uint32_t) * args->num_handles, GFP_KERNEL);
1231 if (!lock_list) {
1232 DRM_ERROR("Unable allocate memory for lock list\n");
1233 result = -ENOMEM;
1234 goto error;
1235 }
1236
1237 if (copy_from_user(lock_list, args->handle_list,
1238 sizeof(uint32_t) * args->num_handles)) {
1239 DRM_ERROR("Unable to copy the lock list from the user\n");
1240 result = -EFAULT;
1241 goto free_handle_list;
1242 }
1243
1244
1245 work_list = lock_list;
1246 mutex_lock(&dev->struct_mutex);
1247
1248 /* build the fence for this group of handles */
1249 fence_index = find_empty_fence();
1250 if (fence_index == ENTRY_EMPTY) {
1251 DRM_ERROR("Unable to find a empty fence\n");
1252 args->lock_id = 0xDEADBEEF;
1253 result = -EFAULT;
1254 goto out_unlock;
1255 }
1256
1257 fence = &gem_buf_fence[fence_index];
1258 gem_buf_fence[fence_index].num_buffers = args->num_handles;
1259 args->lock_id = gem_buf_fence[fence_index].fence_id;
1260
1261 for (j = args->num_handles; j > 0; j--, lock_list++) {
1262 obj = drm_gem_object_lookup(dev, file_priv, *lock_list);
1263
1264 if (obj == NULL) {
1265 DRM_ERROR("Invalid GEM handle %x\n", *lock_list);
1266 result = -EBADF;
1267 goto out_unlock;
1268 }
1269
1270 priv = obj->driver_private;
1271 this_fence_entry = NULL;
1272
1273 /* get a fence entry to hook into the fence */
1274 for (i = 0; i < DRM_KGSL_NUM_FENCE_ENTRIES; i++) {
1275 if (!priv->fence_entries[i].in_use) {
1276 this_fence_entry = &priv->fence_entries[i];
1277 this_fence_entry->in_use = 1;
1278 break;
1279 }
1280 }
1281
1282 if (this_fence_entry == NULL) {
1283 fence->num_buffers = 0;
1284 fence->fence_id = ENTRY_EMPTY;
1285 args->lock_id = 0xDEADBEAD;
1286 result = -EFAULT;
1287 drm_gem_object_unreference(obj);
1288 goto out_unlock;
1289 }
1290
1291 /* We're trying to lock - add to a fence */
1292 list_add((struct list_head *)this_fence_entry,
1293 &gem_buf_fence[fence_index].buffers_in_fence);
1294 if (priv->lockpid) {
1295
1296 if (priv->lockpid == args->pid) {
1297 /* now that things are running async this */
1298 /* happens when an op isn't done */
1299 /* so it's already locked by the calling pid */
1300 continue;
1301 }
1302
1303
1304 /* if a pid already had it locked */
1305 /* create and add to wait list */
1306 for (i = 0; i < DRM_KGSL_HANDLE_WAIT_ENTRIES; i++) {
1307 if (priv->wait_entries[i].in_use == 0) {
1308 /* this one is empty */
1309 lock_item = &priv->wait_entries[i];
1310 lock_item->in_use = 1;
1311 lock_item->pid = args->pid;
1312 INIT_LIST_HEAD((struct list_head *)
1313 &priv->wait_entries[i]);
1314 break;
1315 }
1316 }
1317
1318 if (i == DRM_KGSL_HANDLE_WAIT_ENTRIES) {
1319
1320 result = -EFAULT;
1321 drm_gem_object_unreference(obj);
1322 goto out_unlock;
1323 }
1324
1325 list_add_tail((struct list_head *)&lock_item->list,
1326 &priv->wait_list);
1327 mutex_unlock(&dev->struct_mutex);
1328 /* here we need to block */
1329 wait_event_interruptible_timeout(
1330 priv->wait_entries[i].process_wait_q,
1331 (priv->lockpid == 0),
1332 msecs_to_jiffies(64));
1333 mutex_lock(&dev->struct_mutex);
1334 lock_item->in_use = 0;
1335 }
1336
1337 /* Getting here means no one currently holds the lock */
1338 priv->lockpid = args->pid;
1339
1340 args->lock_id = gem_buf_fence[fence_index].fence_id;
1341 }
1342 fence->lockpid = args->pid;
1343
1344out_unlock:
1345 mutex_unlock(&dev->struct_mutex);
1346
1347free_handle_list:
1348 kfree(work_list);
1349
1350error:
1351 return result;
1352}
1353
1354int
1355kgsl_gem_unlock_handle_ioctl(struct drm_device *dev, void *data,
1356 struct drm_file *file_priv)
1357{
1358 struct drm_kgsl_gem_unlock_handles *args = data;
1359 int result = 0;
1360 int32_t fence_index;
1361
1362 mutex_lock(&dev->struct_mutex);
1363 fence_index = find_fence(args->lock_id);
1364 if (fence_index == ENTRY_EMPTY) {
1365 DRM_ERROR("Invalid lock ID: %x\n", args->lock_id);
1366 result = -EFAULT;
1367 goto out_unlock;
1368 }
1369
1370 cleanup_fence(&gem_buf_fence[fence_index], 1);
1371
1372out_unlock:
1373 mutex_unlock(&dev->struct_mutex);
1374
1375 return result;
1376}
1377
1378
1379int
1380kgsl_gem_unlock_on_ts_ioctl(struct drm_device *dev, void *data,
1381 struct drm_file *file_priv)
1382{
1383 struct drm_kgsl_gem_unlock_on_ts *args = data;
1384 int result = 0;
1385 int ts_done = 0;
1386 int32_t fence_index, ts_device;
1387 struct drm_kgsl_gem_object_fence *fence;
1388 struct kgsl_device *device;
1389
1390 if (args->type == DRM_KGSL_GEM_TS_3D)
1391 ts_device = KGSL_DEVICE_3D0;
1392 else if (args->type == DRM_KGSL_GEM_TS_2D)
1393 ts_device = KGSL_DEVICE_2D0;
1394 else {
1395 result = -EINVAL;
1396 goto error;
1397 }
1398
1399 device = kgsl_get_device(ts_device);
Wei Zouc8c01632012-03-24 17:27:26 -07001400 ts_done = kgsl_check_timestamp(device, args->timestamp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001401
1402 mutex_lock(&dev->struct_mutex);
1403
1404 fence_index = find_fence(args->lock_id);
1405 if (fence_index == ENTRY_EMPTY) {
1406 DRM_ERROR("Invalid lock ID: %x\n", args->lock_id);
1407 result = -EFAULT;
1408 goto out_unlock;
1409 }
1410
1411 fence = &gem_buf_fence[fence_index];
1412 fence->ts_device = ts_device;
1413
1414 if (!ts_done)
1415 fence->ts_valid = 1;
1416 else
1417 cleanup_fence(fence, 1);
1418
1419
1420out_unlock:
1421 mutex_unlock(&dev->struct_mutex);
1422
1423error:
1424 return result;
1425}
1426
1427struct drm_ioctl_desc kgsl_drm_ioctls[] = {
1428 DRM_IOCTL_DEF_DRV(KGSL_GEM_CREATE, kgsl_gem_create_ioctl, 0),
1429 DRM_IOCTL_DEF_DRV(KGSL_GEM_PREP, kgsl_gem_prep_ioctl, 0),
1430 DRM_IOCTL_DEF_DRV(KGSL_GEM_SETMEMTYPE, kgsl_gem_setmemtype_ioctl, 0),
1431 DRM_IOCTL_DEF_DRV(KGSL_GEM_GETMEMTYPE, kgsl_gem_getmemtype_ioctl, 0),
1432 DRM_IOCTL_DEF_DRV(KGSL_GEM_BIND_GPU, kgsl_gem_bind_gpu_ioctl, 0),
1433 DRM_IOCTL_DEF_DRV(KGSL_GEM_UNBIND_GPU, kgsl_gem_unbind_gpu_ioctl, 0),
1434 DRM_IOCTL_DEF_DRV(KGSL_GEM_ALLOC, kgsl_gem_alloc_ioctl, 0),
1435 DRM_IOCTL_DEF_DRV(KGSL_GEM_MMAP, kgsl_gem_mmap_ioctl, 0),
1436 DRM_IOCTL_DEF_DRV(KGSL_GEM_GET_BUFINFO, kgsl_gem_get_bufinfo_ioctl, 0),
1437 DRM_IOCTL_DEF_DRV(KGSL_GEM_SET_BUFCOUNT,
1438 kgsl_gem_set_bufcount_ioctl, 0),
1439 DRM_IOCTL_DEF_DRV(KGSL_GEM_SET_ACTIVE, kgsl_gem_set_active_ioctl, 0),
1440 DRM_IOCTL_DEF_DRV(KGSL_GEM_LOCK_HANDLE,
1441 kgsl_gem_lock_handle_ioctl, 0),
1442 DRM_IOCTL_DEF_DRV(KGSL_GEM_UNLOCK_HANDLE,
1443 kgsl_gem_unlock_handle_ioctl, 0),
1444 DRM_IOCTL_DEF_DRV(KGSL_GEM_UNLOCK_ON_TS,
1445 kgsl_gem_unlock_on_ts_ioctl, 0),
1446 DRM_IOCTL_DEF_DRV(KGSL_GEM_CREATE_FD, kgsl_gem_create_fd_ioctl,
1447 DRM_MASTER),
1448};
1449
1450static struct drm_driver driver = {
Michael Street8bacdd02012-01-05 14:55:01 -08001451 .driver_features = DRIVER_GEM,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001452 .load = kgsl_drm_load,
1453 .unload = kgsl_drm_unload,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001454 .preclose = kgsl_drm_preclose,
1455 .suspend = kgsl_drm_suspend,
1456 .resume = kgsl_drm_resume,
1457 .reclaim_buffers = drm_core_reclaim_buffers,
1458 .gem_init_object = kgsl_gem_init_object,
1459 .gem_free_object = kgsl_gem_free_object,
1460 .ioctls = kgsl_drm_ioctls,
1461
1462 .fops = {
1463 .owner = THIS_MODULE,
1464 .open = drm_open,
1465 .release = drm_release,
1466 .unlocked_ioctl = drm_ioctl,
1467 .mmap = msm_drm_gem_mmap,
1468 .poll = drm_poll,
1469 .fasync = drm_fasync,
1470 },
1471
1472 .name = DRIVER_NAME,
1473 .desc = DRIVER_DESC,
1474 .date = DRIVER_DATE,
1475 .major = DRIVER_MAJOR,
1476 .minor = DRIVER_MINOR,
1477 .patchlevel = DRIVER_PATCHLEVEL,
1478};
1479
1480int kgsl_drm_init(struct platform_device *dev)
1481{
1482 int i;
1483
Michael Street8bacdd02012-01-05 14:55:01 -08001484 /* Only initialize once */
1485 if (kgsl_drm_inited == DRM_KGSL_INITED)
1486 return 0;
1487
1488 kgsl_drm_inited = DRM_KGSL_INITED;
1489
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001490 driver.num_ioctls = DRM_ARRAY_SIZE(kgsl_drm_ioctls);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001491
1492 INIT_LIST_HEAD(&kgsl_mem_list);
1493
1494 for (i = 0; i < DRM_KGSL_NUM_FENCE_ENTRIES; i++) {
1495 gem_buf_fence[i].num_buffers = 0;
1496 gem_buf_fence[i].ts_valid = 0;
1497 gem_buf_fence[i].fence_id = ENTRY_EMPTY;
1498 }
1499
Michael Street8bacdd02012-01-05 14:55:01 -08001500 return drm_platform_init(&driver, dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001501}
1502
1503void kgsl_drm_exit(void)
1504{
Michael Street8bacdd02012-01-05 14:55:01 -08001505 kgsl_drm_inited = DRM_KGSL_NOT_INITED;
1506 drm_platform_exit(&driver, driver.kdriver.platform_device);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001507}