blob: 9e9bbf27ab22f9048408ec97be7964be92bd0f30 [file] [log] [blame]
Tarun Karraf8e5cd22012-01-09 14:10:09 -07001/* Copyright (c) 2008-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#include <linux/fb.h>
14#include <linux/file.h>
15#include <linux/fs.h>
16#include <linux/debugfs.h>
17#include <linux/uaccess.h>
18#include <linux/interrupt.h>
19#include <linux/workqueue.h>
20#include <linux/android_pmem.h>
21#include <linux/vmalloc.h>
22#include <linux/pm_runtime.h>
Jordan Croused4bc9d22011-11-17 13:39:21 -070023#include <linux/genlock.h>
Jordan Crousec9559e42012-04-05 16:55:56 -060024#include <linux/rbtree.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070025#include <linux/ashmem.h>
26#include <linux/major.h>
Jordan Crouse8eab35a2011-10-12 16:57:48 -060027#include <linux/ion.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070028
29#include "kgsl.h"
30#include "kgsl_debugfs.h"
31#include "kgsl_cffdump.h"
32#include "kgsl_log.h"
33#include "kgsl_sharedmem.h"
34#include "kgsl_device.h"
Norman Geed7402ff2011-10-28 08:51:11 -060035#include "kgsl_trace.h"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070036
37#undef MODULE_PARAM_PREFIX
38#define MODULE_PARAM_PREFIX "kgsl."
39
40static int kgsl_pagetable_count = KGSL_PAGETABLE_COUNT;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -060041static char *ksgl_mmu_type;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070042module_param_named(ptcount, kgsl_pagetable_count, int, 0);
43MODULE_PARM_DESC(kgsl_pagetable_count,
44"Minimum number of pagetables for KGSL to allocate at initialization time");
Shubhraprakash Das767fdda2011-08-15 15:49:45 -060045module_param_named(mmutype, ksgl_mmu_type, charp, 0);
46MODULE_PARM_DESC(ksgl_mmu_type,
47"Type of MMU to be used for graphics. Valid values are 'iommu' or 'gpummu' or 'nommu'");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070048
Jordan Crouse8eab35a2011-10-12 16:57:48 -060049static struct ion_client *kgsl_ion_client;
50
Jordan Croused4bc9d22011-11-17 13:39:21 -070051/**
52 * kgsl_add_event - Add a new timstamp event for the KGSL device
53 * @device - KGSL device for the new event
54 * @ts - the timestamp to trigger the event on
55 * @cb - callback function to call when the timestamp expires
56 * @priv - private data for the specific event type
Jeremy Gebbenfd87f9a2012-02-10 07:06:09 -070057 * @owner - driver instance that owns this event
Jordan Croused4bc9d22011-11-17 13:39:21 -070058 *
59 * @returns - 0 on success or error code on failure
60 */
61
Carter Cooper7e7f02e2012-02-15 09:36:31 -070062static int kgsl_add_event(struct kgsl_device *device, u32 id, u32 ts,
63 void (*cb)(struct kgsl_device *, void *, u32, u32), void *priv,
Jeremy Gebbenfd87f9a2012-02-10 07:06:09 -070064 struct kgsl_device_private *owner)
Jordan Croused4bc9d22011-11-17 13:39:21 -070065{
66 struct kgsl_event *event;
67 struct list_head *n;
Carter Cooper7e7f02e2012-02-15 09:36:31 -070068 unsigned int cur_ts;
69 struct kgsl_context *context = NULL;
Jordan Croused4bc9d22011-11-17 13:39:21 -070070
71 if (cb == NULL)
72 return -EINVAL;
73
Carter Cooper7e7f02e2012-02-15 09:36:31 -070074 if (id != KGSL_MEMSTORE_GLOBAL) {
75 context = idr_find(&device->context_idr, id);
76 if (context == NULL)
77 return -EINVAL;
78 }
79 cur_ts = device->ftbl->readtimestamp(device, context,
80 KGSL_TIMESTAMP_RETIRED);
81
Jordan Croused4bc9d22011-11-17 13:39:21 -070082 /* Check to see if the requested timestamp has already fired */
83
Carter Cooper7e7f02e2012-02-15 09:36:31 -070084 if (timestamp_cmp(cur_ts, ts) >= 0) {
85 cb(device, priv, id, cur_ts);
Jordan Croused4bc9d22011-11-17 13:39:21 -070086 return 0;
87 }
88
89 event = kzalloc(sizeof(*event), GFP_KERNEL);
90 if (event == NULL)
91 return -ENOMEM;
92
Carter Cooper7e7f02e2012-02-15 09:36:31 -070093 event->context = context;
Jordan Croused4bc9d22011-11-17 13:39:21 -070094 event->timestamp = ts;
95 event->priv = priv;
96 event->func = cb;
Jeremy Gebbenfd87f9a2012-02-10 07:06:09 -070097 event->owner = owner;
Jordan Croused4bc9d22011-11-17 13:39:21 -070098
Carter Cooper7e7f02e2012-02-15 09:36:31 -070099 /*
100 * Add the event in order to the list. Order is by context id
101 * first and then by timestamp for that context.
102 */
Jordan Croused4bc9d22011-11-17 13:39:21 -0700103
104 for (n = device->events.next ; n != &device->events; n = n->next) {
105 struct kgsl_event *e =
106 list_entry(n, struct kgsl_event, list);
107
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700108 if (e->context != context)
109 continue;
110
Jordan Croused4bc9d22011-11-17 13:39:21 -0700111 if (timestamp_cmp(e->timestamp, ts) > 0) {
112 list_add(&event->list, n->prev);
113 break;
114 }
115 }
116
117 if (n == &device->events)
118 list_add_tail(&event->list, &device->events);
119
Jeremy Gebben63904832012-02-07 16:10:55 -0700120 queue_work(device->work_queue, &device->ts_expired_ws);
Jordan Croused4bc9d22011-11-17 13:39:21 -0700121 return 0;
122}
Jordan Croused4bc9d22011-11-17 13:39:21 -0700123
Jeremy Gebbenfd87f9a2012-02-10 07:06:09 -0700124/**
125 * kgsl_cancel_events - Cancel all events for a process
126 * @device - KGSL device for the events to cancel
127 * @owner - driver instance that owns the events to cancel
128 *
129 */
130static void kgsl_cancel_events(struct kgsl_device *device,
131 struct kgsl_device_private *owner)
132{
133 struct kgsl_event *event, *event_tmp;
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700134 unsigned int id, cur;
Jeremy Gebbenfd87f9a2012-02-10 07:06:09 -0700135
136 list_for_each_entry_safe(event, event_tmp, &device->events, list) {
137 if (event->owner != owner)
138 continue;
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700139
140 cur = device->ftbl->readtimestamp(device, event->context,
141 KGSL_TIMESTAMP_RETIRED);
142
143 id = event->context ? event->context->id : KGSL_MEMSTORE_GLOBAL;
Jeremy Gebbenfd87f9a2012-02-10 07:06:09 -0700144 /*
145 * "cancel" the events by calling their callback.
146 * Currently, events are used for lock and memory
147 * management, so if the process is dying the right
148 * thing to do is release or free.
149 */
150 if (event->func)
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700151 event->func(device, event->priv, id, cur);
Jeremy Gebbenfd87f9a2012-02-10 07:06:09 -0700152
153 list_del(&event->list);
154 kfree(event);
155 }
156}
157
Jordan Crouse0fdf3a02012-03-16 14:53:41 -0600158/* kgsl_get_mem_entry - get the mem_entry structure for the specified object
159 * @ptbase - the pagetable base of the object
160 * @gpuaddr - the GPU address of the object
161 * @size - Size of the region to search
162 */
163
164struct kgsl_mem_entry *kgsl_get_mem_entry(unsigned int ptbase,
165 unsigned int gpuaddr, unsigned int size)
166{
167 struct kgsl_process_private *priv;
168 struct kgsl_mem_entry *entry;
169
170 mutex_lock(&kgsl_driver.process_mutex);
171
172 list_for_each_entry(priv, &kgsl_driver.process_list, list) {
173 if (!kgsl_mmu_pt_equal(priv->pagetable, ptbase))
174 continue;
175 spin_lock(&priv->mem_lock);
176 entry = kgsl_sharedmem_find_region(priv, gpuaddr, size);
177
178 if (entry) {
179 spin_unlock(&priv->mem_lock);
180 mutex_unlock(&kgsl_driver.process_mutex);
181 return entry;
182 }
183 spin_unlock(&priv->mem_lock);
184 }
185 mutex_unlock(&kgsl_driver.process_mutex);
186
187 return NULL;
188}
189EXPORT_SYMBOL(kgsl_get_mem_entry);
190
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700191static inline struct kgsl_mem_entry *
192kgsl_mem_entry_create(void)
193{
194 struct kgsl_mem_entry *entry = kzalloc(sizeof(*entry), GFP_KERNEL);
195
196 if (!entry)
197 KGSL_CORE_ERR("kzalloc(%d) failed\n", sizeof(*entry));
198 else
199 kref_init(&entry->refcount);
200
201 return entry;
202}
203
204void
205kgsl_mem_entry_destroy(struct kref *kref)
206{
207 struct kgsl_mem_entry *entry = container_of(kref,
208 struct kgsl_mem_entry,
209 refcount);
Jordan Crouse1b897cf2011-10-12 16:57:48 -0600210
Jordan Crouse1b897cf2011-10-12 16:57:48 -0600211 if (entry->memtype != KGSL_MEM_ENTRY_KERNEL)
212 kgsl_driver.stats.mapped -= entry->memdesc.size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700213
Jordan Crouse8eab35a2011-10-12 16:57:48 -0600214 /*
215 * Ion takes care of freeing the sglist for us (how nice </sarcasm>) so
216 * unmap the dma before freeing the sharedmem so kgsl_sharedmem_free
217 * doesn't try to free it again
218 */
219
220 if (entry->memtype == KGSL_MEM_ENTRY_ION) {
221 ion_unmap_dma(kgsl_ion_client, entry->priv_data);
222 entry->memdesc.sg = NULL;
223 }
224
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700225 kgsl_sharedmem_free(&entry->memdesc);
226
Jordan Crouse1b897cf2011-10-12 16:57:48 -0600227 switch (entry->memtype) {
228 case KGSL_MEM_ENTRY_PMEM:
229 case KGSL_MEM_ENTRY_ASHMEM:
230 if (entry->priv_data)
231 fput(entry->priv_data);
232 break;
Jordan Crouse8eab35a2011-10-12 16:57:48 -0600233 case KGSL_MEM_ENTRY_ION:
234 ion_free(kgsl_ion_client, entry->priv_data);
235 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700236 }
237
238 kfree(entry);
239}
240EXPORT_SYMBOL(kgsl_mem_entry_destroy);
241
242static
243void kgsl_mem_entry_attach_process(struct kgsl_mem_entry *entry,
244 struct kgsl_process_private *process)
245{
Jordan Crousec9559e42012-04-05 16:55:56 -0600246 struct rb_node **node;
247 struct rb_node *parent = NULL;
248
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700249 spin_lock(&process->mem_lock);
Jordan Crousec9559e42012-04-05 16:55:56 -0600250
251 node = &process->mem_rb.rb_node;
252
253 while (*node) {
254 struct kgsl_mem_entry *cur;
255
256 parent = *node;
257 cur = rb_entry(parent, struct kgsl_mem_entry, node);
258
259 if (entry->memdesc.gpuaddr < cur->memdesc.gpuaddr)
260 node = &parent->rb_left;
261 else
262 node = &parent->rb_right;
263 }
264
265 rb_link_node(&entry->node, parent, node);
266 rb_insert_color(&entry->node, &process->mem_rb);
267
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700268 spin_unlock(&process->mem_lock);
269
270 entry->priv = process;
271}
272
Jordan Crouse00714012012-03-16 14:53:40 -0600273/* Detach a memory entry from a process and unmap it from the MMU */
274
275static void kgsl_mem_entry_detach_process(struct kgsl_mem_entry *entry)
276{
277 if (entry == NULL)
278 return;
279
280 entry->priv->stats[entry->memtype].cur -= entry->memdesc.size;
281 entry->priv = NULL;
282
283 kgsl_mmu_unmap(entry->memdesc.pagetable, &entry->memdesc);
284
285 kgsl_mem_entry_put(entry);
286}
287
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700288/* Allocate a new context id */
289
290static struct kgsl_context *
291kgsl_create_context(struct kgsl_device_private *dev_priv)
292{
293 struct kgsl_context *context;
294 int ret, id;
295
296 context = kzalloc(sizeof(*context), GFP_KERNEL);
297
298 if (context == NULL)
299 return NULL;
300
301 while (1) {
302 if (idr_pre_get(&dev_priv->device->context_idr,
303 GFP_KERNEL) == 0) {
304 kfree(context);
305 return NULL;
306 }
307
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700308 ret = idr_get_new_above(&dev_priv->device->context_idr,
309 context, 1, &id);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700310
311 if (ret != -EAGAIN)
312 break;
313 }
314
315 if (ret) {
316 kfree(context);
317 return NULL;
318 }
319
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700320 /* MAX - 1, there is one memdesc in memstore for device info */
321 if (id >= KGSL_MEMSTORE_MAX) {
322 KGSL_DRV_ERR(dev_priv->device, "cannot have more than %d "
323 "ctxts due to memstore limitation\n",
324 KGSL_MEMSTORE_MAX);
325 idr_remove(&dev_priv->device->context_idr, id);
326 kfree(context);
327 return NULL;
328 }
329
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700330 context->id = id;
331 context->dev_priv = dev_priv;
332
333 return context;
334}
335
336static void
337kgsl_destroy_context(struct kgsl_device_private *dev_priv,
338 struct kgsl_context *context)
339{
340 int id;
341
342 if (context == NULL)
343 return;
344
345 /* Fire a bug if the devctxt hasn't been freed */
346 BUG_ON(context->devctxt);
347
348 id = context->id;
349 kfree(context);
350
351 idr_remove(&dev_priv->device->context_idr, id);
352}
353
Jordan Crouse1bf80aa2011-10-12 16:57:47 -0600354static void kgsl_timestamp_expired(struct work_struct *work)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700355{
Jordan Crouse1bf80aa2011-10-12 16:57:47 -0600356 struct kgsl_device *device = container_of(work, struct kgsl_device,
357 ts_expired_ws);
Jordan Croused4bc9d22011-11-17 13:39:21 -0700358 struct kgsl_event *event, *event_tmp;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700359 uint32_t ts_processed;
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700360 unsigned int id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700361
Jordan Crouse1bf80aa2011-10-12 16:57:47 -0600362 mutex_lock(&device->mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700363
Jordan Croused4bc9d22011-11-17 13:39:21 -0700364 /* Process expired events */
365 list_for_each_entry_safe(event, event_tmp, &device->events, list) {
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700366 ts_processed = device->ftbl->readtimestamp(device,
367 event->context, KGSL_TIMESTAMP_RETIRED);
Jordan Croused4bc9d22011-11-17 13:39:21 -0700368 if (timestamp_cmp(ts_processed, event->timestamp) < 0)
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700369 continue;
370
371 id = event->context ? event->context->id : KGSL_MEMSTORE_GLOBAL;
Jordan Croused4bc9d22011-11-17 13:39:21 -0700372
373 if (event->func)
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700374 event->func(device, event->priv, id, ts_processed);
Jordan Croused4bc9d22011-11-17 13:39:21 -0700375
376 list_del(&event->list);
377 kfree(event);
378 }
379
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700380 device->last_expired_ctxt_id = KGSL_CONTEXT_INVALID;
381
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700382 mutex_unlock(&device->mutex);
383}
384
385static void kgsl_check_idle_locked(struct kgsl_device *device)
386{
387 if (device->pwrctrl.nap_allowed == true &&
388 device->state == KGSL_STATE_ACTIVE &&
389 device->requested_state == KGSL_STATE_NONE) {
Jeremy Gebben388c2972011-12-16 09:05:07 -0700390 kgsl_pwrctrl_request_state(device, KGSL_STATE_NAP);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700391 if (kgsl_pwrctrl_sleep(device) != 0)
392 mod_timer(&device->idle_timer,
393 jiffies +
394 device->pwrctrl.interval_timeout);
395 }
396}
397
398static void kgsl_check_idle(struct kgsl_device *device)
399{
400 mutex_lock(&device->mutex);
401 kgsl_check_idle_locked(device);
402 mutex_unlock(&device->mutex);
403}
404
405struct kgsl_device *kgsl_get_device(int dev_idx)
406{
407 int i;
408 struct kgsl_device *ret = NULL;
409
410 mutex_lock(&kgsl_driver.devlock);
411
412 for (i = 0; i < KGSL_DEVICE_MAX; i++) {
413 if (kgsl_driver.devp[i] && kgsl_driver.devp[i]->id == dev_idx) {
414 ret = kgsl_driver.devp[i];
415 break;
416 }
417 }
418
419 mutex_unlock(&kgsl_driver.devlock);
420 return ret;
421}
422EXPORT_SYMBOL(kgsl_get_device);
423
424static struct kgsl_device *kgsl_get_minor(int minor)
425{
426 struct kgsl_device *ret = NULL;
427
428 if (minor < 0 || minor >= KGSL_DEVICE_MAX)
429 return NULL;
430
431 mutex_lock(&kgsl_driver.devlock);
432 ret = kgsl_driver.devp[minor];
433 mutex_unlock(&kgsl_driver.devlock);
434
435 return ret;
436}
437
438int kgsl_register_ts_notifier(struct kgsl_device *device,
439 struct notifier_block *nb)
440{
441 BUG_ON(device == NULL);
442 return atomic_notifier_chain_register(&device->ts_notifier_list,
443 nb);
444}
445EXPORT_SYMBOL(kgsl_register_ts_notifier);
446
447int kgsl_unregister_ts_notifier(struct kgsl_device *device,
448 struct notifier_block *nb)
449{
450 BUG_ON(device == NULL);
451 return atomic_notifier_chain_unregister(&device->ts_notifier_list,
452 nb);
453}
454EXPORT_SYMBOL(kgsl_unregister_ts_notifier);
455
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700456int kgsl_check_timestamp(struct kgsl_device *device,
457 struct kgsl_context *context, unsigned int timestamp)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700458{
459 unsigned int ts_processed;
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700460 unsigned int global;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700461
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700462 ts_processed = device->ftbl->readtimestamp(device, context,
463 KGSL_TIMESTAMP_RETIRED);
464 global = device->ftbl->readtimestamp(device, NULL,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700465 KGSL_TIMESTAMP_RETIRED);
466
Jordan Crousee6239dd2011-11-17 13:39:21 -0700467 return (timestamp_cmp(ts_processed, timestamp) >= 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700468}
469EXPORT_SYMBOL(kgsl_check_timestamp);
470
471static int kgsl_suspend_device(struct kgsl_device *device, pm_message_t state)
472{
473 int status = -EINVAL;
474 unsigned int nap_allowed_saved;
475 struct kgsl_pwrscale_policy *policy_saved;
476
477 if (!device)
478 return -EINVAL;
479
480 KGSL_PWR_WARN(device, "suspend start\n");
481
482 mutex_lock(&device->mutex);
483 nap_allowed_saved = device->pwrctrl.nap_allowed;
484 device->pwrctrl.nap_allowed = false;
485 policy_saved = device->pwrscale.policy;
486 device->pwrscale.policy = NULL;
Jeremy Gebben388c2972011-12-16 09:05:07 -0700487 kgsl_pwrctrl_request_state(device, KGSL_STATE_SUSPEND);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700488 /* Make sure no user process is waiting for a timestamp *
489 * before supending */
490 if (device->active_cnt != 0) {
491 mutex_unlock(&device->mutex);
492 wait_for_completion(&device->suspend_gate);
493 mutex_lock(&device->mutex);
494 }
Suman Tatiraju4a32c652012-02-17 11:59:05 -0800495 /* Don't let the timer wake us during suspended sleep. */
496 del_timer_sync(&device->idle_timer);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700497 switch (device->state) {
498 case KGSL_STATE_INIT:
499 break;
500 case KGSL_STATE_ACTIVE:
501 /* Wait for the device to become idle */
502 device->ftbl->idle(device, KGSL_TIMEOUT_DEFAULT);
503 case KGSL_STATE_NAP:
504 case KGSL_STATE_SLEEP:
505 /* Get the completion ready to be waited upon. */
506 INIT_COMPLETION(device->hwaccess_gate);
507 device->ftbl->suspend_context(device);
508 device->ftbl->stop(device);
Jeremy Gebben388c2972011-12-16 09:05:07 -0700509 kgsl_pwrctrl_set_state(device, KGSL_STATE_SUSPEND);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700510 break;
Suman Tatiraju24569022011-10-27 11:11:12 -0700511 case KGSL_STATE_SLUMBER:
512 INIT_COMPLETION(device->hwaccess_gate);
Jeremy Gebben388c2972011-12-16 09:05:07 -0700513 kgsl_pwrctrl_set_state(device, KGSL_STATE_SUSPEND);
Suman Tatiraju24569022011-10-27 11:11:12 -0700514 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700515 default:
516 KGSL_PWR_ERR(device, "suspend fail, device %d\n",
517 device->id);
518 goto end;
519 }
Jeremy Gebben388c2972011-12-16 09:05:07 -0700520 kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700521 device->pwrctrl.nap_allowed = nap_allowed_saved;
522 device->pwrscale.policy = policy_saved;
523 status = 0;
524
525end:
526 mutex_unlock(&device->mutex);
527 KGSL_PWR_WARN(device, "suspend end\n");
528 return status;
529}
530
531static int kgsl_resume_device(struct kgsl_device *device)
532{
533 int status = -EINVAL;
534
535 if (!device)
536 return -EINVAL;
537
538 KGSL_PWR_WARN(device, "resume start\n");
539 mutex_lock(&device->mutex);
540 if (device->state == KGSL_STATE_SUSPEND) {
Jeremy Gebben388c2972011-12-16 09:05:07 -0700541 kgsl_pwrctrl_set_state(device, KGSL_STATE_SLUMBER);
Suman Tatiraju24569022011-10-27 11:11:12 -0700542 status = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700543 complete_all(&device->hwaccess_gate);
544 }
Jeremy Gebben388c2972011-12-16 09:05:07 -0700545 kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700546
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700547 mutex_unlock(&device->mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700548 KGSL_PWR_WARN(device, "resume end\n");
549 return status;
550}
551
552static int kgsl_suspend(struct device *dev)
553{
554
555 pm_message_t arg = {0};
556 struct kgsl_device *device = dev_get_drvdata(dev);
557 return kgsl_suspend_device(device, arg);
558}
559
560static int kgsl_resume(struct device *dev)
561{
562 struct kgsl_device *device = dev_get_drvdata(dev);
563 return kgsl_resume_device(device);
564}
565
566static int kgsl_runtime_suspend(struct device *dev)
567{
568 return 0;
569}
570
571static int kgsl_runtime_resume(struct device *dev)
572{
573 return 0;
574}
575
576const struct dev_pm_ops kgsl_pm_ops = {
577 .suspend = kgsl_suspend,
578 .resume = kgsl_resume,
579 .runtime_suspend = kgsl_runtime_suspend,
580 .runtime_resume = kgsl_runtime_resume,
581};
582EXPORT_SYMBOL(kgsl_pm_ops);
583
584void kgsl_early_suspend_driver(struct early_suspend *h)
585{
586 struct kgsl_device *device = container_of(h,
587 struct kgsl_device, display_off);
Suman Tatiraju24569022011-10-27 11:11:12 -0700588 KGSL_PWR_WARN(device, "early suspend start\n");
Ranjhith Kalisamy8b636952011-09-03 14:48:31 +0530589 mutex_lock(&device->mutex);
Lucille Sylvester344e4622012-01-18 15:53:21 -0700590 kgsl_pwrctrl_request_state(device, KGSL_STATE_SLUMBER);
Suman Tatiraju24569022011-10-27 11:11:12 -0700591 kgsl_pwrctrl_sleep(device);
Ranjhith Kalisamy8b636952011-09-03 14:48:31 +0530592 mutex_unlock(&device->mutex);
Suman Tatiraju24569022011-10-27 11:11:12 -0700593 KGSL_PWR_WARN(device, "early suspend end\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700594}
595EXPORT_SYMBOL(kgsl_early_suspend_driver);
596
597int kgsl_suspend_driver(struct platform_device *pdev,
598 pm_message_t state)
599{
600 struct kgsl_device *device = dev_get_drvdata(&pdev->dev);
601 return kgsl_suspend_device(device, state);
602}
603EXPORT_SYMBOL(kgsl_suspend_driver);
604
605int kgsl_resume_driver(struct platform_device *pdev)
606{
607 struct kgsl_device *device = dev_get_drvdata(&pdev->dev);
608 return kgsl_resume_device(device);
609}
610EXPORT_SYMBOL(kgsl_resume_driver);
611
612void kgsl_late_resume_driver(struct early_suspend *h)
613{
614 struct kgsl_device *device = container_of(h,
615 struct kgsl_device, display_off);
Suman Tatiraju24569022011-10-27 11:11:12 -0700616 KGSL_PWR_WARN(device, "late resume start\n");
Ranjhith Kalisamy8b636952011-09-03 14:48:31 +0530617 mutex_lock(&device->mutex);
Suman Tatiraju24569022011-10-27 11:11:12 -0700618 device->pwrctrl.restore_slumber = 0;
Suman Tatiraju3005cdd2012-03-19 14:38:11 -0700619 kgsl_pwrctrl_wake(device);
Ranjhith Kalisamy8b636952011-09-03 14:48:31 +0530620 mutex_unlock(&device->mutex);
Suman Tatiraju24569022011-10-27 11:11:12 -0700621 kgsl_check_idle(device);
622 KGSL_PWR_WARN(device, "late resume end\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700623}
624EXPORT_SYMBOL(kgsl_late_resume_driver);
625
626/* file operations */
627static struct kgsl_process_private *
628kgsl_get_process_private(struct kgsl_device_private *cur_dev_priv)
629{
630 struct kgsl_process_private *private;
631
632 mutex_lock(&kgsl_driver.process_mutex);
633 list_for_each_entry(private, &kgsl_driver.process_list, list) {
634 if (private->pid == task_tgid_nr(current)) {
635 private->refcnt++;
636 goto out;
637 }
638 }
639
640 /* no existing process private found for this dev_priv, create one */
641 private = kzalloc(sizeof(struct kgsl_process_private), GFP_KERNEL);
642 if (private == NULL) {
643 KGSL_DRV_ERR(cur_dev_priv->device, "kzalloc(%d) failed\n",
644 sizeof(struct kgsl_process_private));
645 goto out;
646 }
647
648 spin_lock_init(&private->mem_lock);
649 private->refcnt = 1;
650 private->pid = task_tgid_nr(current);
Jordan Crousec9559e42012-04-05 16:55:56 -0600651 private->mem_rb = RB_ROOT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700652
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600653 if (kgsl_mmu_enabled())
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700654 {
655 unsigned long pt_name;
656
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700657 pt_name = task_tgid_nr(current);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700658 private->pagetable = kgsl_mmu_getpagetable(pt_name);
659 if (private->pagetable == NULL) {
660 kfree(private);
661 private = NULL;
662 goto out;
663 }
664 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700665
666 list_add(&private->list, &kgsl_driver.process_list);
667
668 kgsl_process_init_sysfs(private);
669
670out:
671 mutex_unlock(&kgsl_driver.process_mutex);
672 return private;
673}
674
675static void
676kgsl_put_process_private(struct kgsl_device *device,
677 struct kgsl_process_private *private)
678{
679 struct kgsl_mem_entry *entry = NULL;
Jordan Crousec9559e42012-04-05 16:55:56 -0600680 struct rb_node *node;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700681
682 if (!private)
683 return;
684
685 mutex_lock(&kgsl_driver.process_mutex);
686
687 if (--private->refcnt)
688 goto unlock;
689
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700690 kgsl_process_uninit_sysfs(private);
691
692 list_del(&private->list);
693
Jordan Crousec9559e42012-04-05 16:55:56 -0600694 for (node = rb_first(&private->mem_rb); node; ) {
695 entry = rb_entry(node, struct kgsl_mem_entry, node);
696 node = rb_next(&entry->node);
697
698 rb_erase(&entry->node, &private->mem_rb);
Jordan Crouse00714012012-03-16 14:53:40 -0600699 kgsl_mem_entry_detach_process(entry);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700700 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700701 kgsl_mmu_putpagetable(private->pagetable);
702 kfree(private);
703unlock:
704 mutex_unlock(&kgsl_driver.process_mutex);
705}
706
707static int kgsl_release(struct inode *inodep, struct file *filep)
708{
709 int result = 0;
Jordan Crouse2db0af92011-08-08 16:05:09 -0600710 struct kgsl_device_private *dev_priv = filep->private_data;
711 struct kgsl_process_private *private = dev_priv->process_priv;
712 struct kgsl_device *device = dev_priv->device;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700713 struct kgsl_context *context;
714 int next = 0;
715
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700716 filep->private_data = NULL;
717
718 mutex_lock(&device->mutex);
719 kgsl_check_suspended(device);
720
721 while (1) {
Jordan Crouse2db0af92011-08-08 16:05:09 -0600722 context = idr_get_next(&device->context_idr, &next);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700723 if (context == NULL)
724 break;
725
726 if (context->dev_priv == dev_priv) {
727 device->ftbl->drawctxt_destroy(device, context);
728 kgsl_destroy_context(dev_priv, context);
729 }
730
731 next = next + 1;
732 }
733
734 device->open_count--;
735 if (device->open_count == 0) {
736 result = device->ftbl->stop(device);
Jeremy Gebben388c2972011-12-16 09:05:07 -0700737 kgsl_pwrctrl_set_state(device, KGSL_STATE_INIT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700738 }
739 /* clean up any to-be-freed entries that belong to this
740 * process and this device
741 */
Jeremy Gebbenfd87f9a2012-02-10 07:06:09 -0700742 kgsl_cancel_events(device, dev_priv);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700743
744 mutex_unlock(&device->mutex);
745 kfree(dev_priv);
746
747 kgsl_put_process_private(device, private);
748
749 pm_runtime_put(device->parentdev);
750 return result;
751}
752
753static int kgsl_open(struct inode *inodep, struct file *filep)
754{
755 int result;
756 struct kgsl_device_private *dev_priv;
757 struct kgsl_device *device;
758 unsigned int minor = iminor(inodep);
759
760 device = kgsl_get_minor(minor);
761 BUG_ON(device == NULL);
762
763 if (filep->f_flags & O_EXCL) {
764 KGSL_DRV_ERR(device, "O_EXCL not allowed\n");
765 return -EBUSY;
766 }
767
768 result = pm_runtime_get_sync(device->parentdev);
769 if (result < 0) {
770 KGSL_DRV_ERR(device,
771 "Runtime PM: Unable to wake up the device, rc = %d\n",
772 result);
773 return result;
774 }
775 result = 0;
776
777 dev_priv = kzalloc(sizeof(struct kgsl_device_private), GFP_KERNEL);
778 if (dev_priv == NULL) {
779 KGSL_DRV_ERR(device, "kzalloc failed(%d)\n",
780 sizeof(struct kgsl_device_private));
781 result = -ENOMEM;
782 goto err_pmruntime;
783 }
784
785 dev_priv->device = device;
786 filep->private_data = dev_priv;
787
788 /* Get file (per process) private struct */
789 dev_priv->process_priv = kgsl_get_process_private(dev_priv);
790 if (dev_priv->process_priv == NULL) {
791 result = -ENOMEM;
792 goto err_freedevpriv;
793 }
794
795 mutex_lock(&device->mutex);
796 kgsl_check_suspended(device);
797
798 if (device->open_count == 0) {
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700799 kgsl_sharedmem_set(&device->memstore, 0, 0,
800 device->memstore.size);
801
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700802 result = device->ftbl->start(device, true);
803
804 if (result) {
805 mutex_unlock(&device->mutex);
806 goto err_putprocess;
807 }
Jeremy Gebben388c2972011-12-16 09:05:07 -0700808 kgsl_pwrctrl_set_state(device, KGSL_STATE_ACTIVE);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700809 }
810 device->open_count++;
811 mutex_unlock(&device->mutex);
812
813 KGSL_DRV_INFO(device, "Initialized %s: mmu=%s pagetable_count=%d\n",
814 device->name, kgsl_mmu_enabled() ? "on" : "off",
815 kgsl_pagetable_count);
816
817 return result;
818
819err_putprocess:
820 kgsl_put_process_private(device, dev_priv->process_priv);
821err_freedevpriv:
822 filep->private_data = NULL;
823 kfree(dev_priv);
824err_pmruntime:
825 pm_runtime_put(device->parentdev);
826 return result;
827}
828
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700829/*call with private->mem_lock locked */
830struct kgsl_mem_entry *
831kgsl_sharedmem_find_region(struct kgsl_process_private *private,
Jordan Crousec9559e42012-04-05 16:55:56 -0600832 unsigned int gpuaddr, size_t size)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700833{
Jordan Crousec9559e42012-04-05 16:55:56 -0600834 struct rb_node *node = private->mem_rb.rb_node;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700835
Jordan Crousec9559e42012-04-05 16:55:56 -0600836 while (node != NULL) {
837 struct kgsl_mem_entry *entry;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700838
Jordan Crousec9559e42012-04-05 16:55:56 -0600839 entry = rb_entry(node, struct kgsl_mem_entry, node);
840
841
842 if (kgsl_gpuaddr_in_memdesc(&entry->memdesc, gpuaddr, size))
843 return entry;
844
845 if (gpuaddr < entry->memdesc.gpuaddr)
846 node = node->rb_left;
847 else if (gpuaddr >=
848 (entry->memdesc.gpuaddr + entry->memdesc.size))
849 node = node->rb_right;
850 else {
851 return NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700852 }
853 }
854
Jordan Crousec9559e42012-04-05 16:55:56 -0600855 return NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700856}
857EXPORT_SYMBOL(kgsl_sharedmem_find_region);
858
Jordan Crousec9559e42012-04-05 16:55:56 -0600859/*call with private->mem_lock locked */
860static inline struct kgsl_mem_entry *
861kgsl_sharedmem_find(struct kgsl_process_private *private, unsigned int gpuaddr)
862{
863 return kgsl_sharedmem_find_region(private, gpuaddr, 1);
864}
865
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700866/*call all ioctl sub functions with driver locked*/
867static long kgsl_ioctl_device_getproperty(struct kgsl_device_private *dev_priv,
868 unsigned int cmd, void *data)
869{
870 int result = 0;
871 struct kgsl_device_getproperty *param = data;
872
873 switch (param->type) {
874 case KGSL_PROP_VERSION:
875 {
876 struct kgsl_version version;
877 if (param->sizebytes != sizeof(version)) {
878 result = -EINVAL;
879 break;
880 }
881
882 version.drv_major = KGSL_VERSION_MAJOR;
883 version.drv_minor = KGSL_VERSION_MINOR;
884 version.dev_major = dev_priv->device->ver_major;
885 version.dev_minor = dev_priv->device->ver_minor;
886
887 if (copy_to_user(param->value, &version, sizeof(version)))
888 result = -EFAULT;
889
890 break;
891 }
Shubhraprakash Das2dfe5dd2012-02-10 13:49:53 -0700892 case KGSL_PROP_GPU_RESET_STAT:
893 {
894 /* Return reset status of given context and clear it */
895 uint32_t id;
896 struct kgsl_context *context;
897
898 if (param->sizebytes != sizeof(unsigned int)) {
899 result = -EINVAL;
900 break;
901 }
902 /* We expect the value passed in to contain the context id */
903 if (copy_from_user(&id, param->value,
904 sizeof(unsigned int))) {
905 result = -EFAULT;
906 break;
907 }
908 context = kgsl_find_context(dev_priv, id);
909 if (!context) {
910 result = -EINVAL;
911 break;
912 }
913 /*
914 * Copy the reset status to value which also serves as
915 * the out parameter
916 */
917 if (copy_to_user(param->value, &(context->reset_status),
918 sizeof(unsigned int))) {
919 result = -EFAULT;
920 break;
921 }
922 /* Clear reset status once its been queried */
923 context->reset_status = KGSL_CTX_STAT_NO_ERROR;
924 break;
925 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700926 default:
927 result = dev_priv->device->ftbl->getproperty(
928 dev_priv->device, param->type,
929 param->value, param->sizebytes);
930 }
931
932
933 return result;
934}
935
Jordan Crouseed7dd7f2012-03-29 13:16:02 -0600936static long kgsl_ioctl_device_setproperty(struct kgsl_device_private *dev_priv,
937 unsigned int cmd, void *data)
938{
939 int result = 0;
940 /* The getproperty struct is reused for setproperty too */
941 struct kgsl_device_getproperty *param = data;
942
943 if (dev_priv->device->ftbl->setproperty)
944 result = dev_priv->device->ftbl->setproperty(
945 dev_priv->device, param->type,
946 param->value, param->sizebytes);
947
948 return result;
949}
950
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700951static long _device_waittimestamp(struct kgsl_device_private *dev_priv,
952 struct kgsl_context *context,
953 unsigned int timestamp,
954 unsigned int timeout)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700955{
956 int result = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700957
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700958 /* Set the active count so that suspend doesn't do the wrong thing */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700959
960 dev_priv->device->active_cnt++;
961
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700962 trace_kgsl_waittimestamp_entry(dev_priv->device,
963 context ? context->id : KGSL_MEMSTORE_GLOBAL,
964 timestamp, timeout);
Norman Geed7402ff2011-10-28 08:51:11 -0600965
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700966 result = dev_priv->device->ftbl->waittimestamp(dev_priv->device,
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700967 context, timestamp, timeout);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700968
Norman Geed7402ff2011-10-28 08:51:11 -0600969 trace_kgsl_waittimestamp_exit(dev_priv->device, result);
970
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700971 /* Fire off any pending suspend operations that are in flight */
972
973 INIT_COMPLETION(dev_priv->device->suspend_gate);
974 dev_priv->device->active_cnt--;
975 complete(&dev_priv->device->suspend_gate);
976
977 return result;
978}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700979
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700980static long kgsl_ioctl_device_waittimestamp(struct kgsl_device_private
981 *dev_priv, unsigned int cmd,
982 void *data)
983{
984 struct kgsl_device_waittimestamp *param = data;
985
986 return _device_waittimestamp(dev_priv, KGSL_MEMSTORE_GLOBAL,
987 param->timestamp, param->timeout);
988}
989
990static long kgsl_ioctl_device_waittimestamp_ctxtid(struct kgsl_device_private
991 *dev_priv, unsigned int cmd,
992 void *data)
993{
994 struct kgsl_device_waittimestamp_ctxtid *param = data;
995 struct kgsl_context *context;
996
997 context = kgsl_find_context(dev_priv, param->context_id);
998 if (context == NULL) {
999 KGSL_DRV_ERR(dev_priv->device, "invalid context_id %d\n",
1000 param->context_id);
1001 return -EINVAL;
1002 }
1003
1004 return _device_waittimestamp(dev_priv, context,
1005 param->timestamp, param->timeout);
1006}
1007
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001008static long kgsl_ioctl_rb_issueibcmds(struct kgsl_device_private *dev_priv,
1009 unsigned int cmd, void *data)
1010{
1011 int result = 0;
1012 struct kgsl_ringbuffer_issueibcmds *param = data;
1013 struct kgsl_ibdesc *ibdesc;
1014 struct kgsl_context *context;
1015
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001016 context = kgsl_find_context(dev_priv, param->drawctxt_id);
1017 if (context == NULL) {
1018 result = -EINVAL;
1019 KGSL_DRV_ERR(dev_priv->device,
Carter Cooper7e7f02e2012-02-15 09:36:31 -07001020 "invalid context_id %d\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001021 param->drawctxt_id);
1022 goto done;
1023 }
1024
1025 if (param->flags & KGSL_CONTEXT_SUBMIT_IB_LIST) {
1026 KGSL_DRV_INFO(dev_priv->device,
1027 "Using IB list mode for ib submission, numibs: %d\n",
1028 param->numibs);
1029 if (!param->numibs) {
1030 KGSL_DRV_ERR(dev_priv->device,
1031 "Invalid numibs as parameter: %d\n",
1032 param->numibs);
1033 result = -EINVAL;
1034 goto done;
1035 }
1036
1037 ibdesc = kzalloc(sizeof(struct kgsl_ibdesc) * param->numibs,
1038 GFP_KERNEL);
1039 if (!ibdesc) {
1040 KGSL_MEM_ERR(dev_priv->device,
1041 "kzalloc(%d) failed\n",
1042 sizeof(struct kgsl_ibdesc) * param->numibs);
1043 result = -ENOMEM;
1044 goto done;
1045 }
1046
1047 if (copy_from_user(ibdesc, (void *)param->ibdesc_addr,
1048 sizeof(struct kgsl_ibdesc) * param->numibs)) {
1049 result = -EFAULT;
1050 KGSL_DRV_ERR(dev_priv->device,
1051 "copy_from_user failed\n");
1052 goto free_ibdesc;
1053 }
1054 } else {
1055 KGSL_DRV_INFO(dev_priv->device,
1056 "Using single IB submission mode for ib submission\n");
1057 /* If user space driver is still using the old mode of
1058 * submitting single ib then we need to support that as well */
1059 ibdesc = kzalloc(sizeof(struct kgsl_ibdesc), GFP_KERNEL);
1060 if (!ibdesc) {
1061 KGSL_MEM_ERR(dev_priv->device,
1062 "kzalloc(%d) failed\n",
1063 sizeof(struct kgsl_ibdesc));
1064 result = -ENOMEM;
1065 goto done;
1066 }
1067 ibdesc[0].gpuaddr = param->ibdesc_addr;
1068 ibdesc[0].sizedwords = param->numibs;
1069 param->numibs = 1;
1070 }
1071
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001072 result = dev_priv->device->ftbl->issueibcmds(dev_priv,
1073 context,
1074 ibdesc,
1075 param->numibs,
1076 &param->timestamp,
1077 param->flags);
1078
Norman Geed7402ff2011-10-28 08:51:11 -06001079 trace_kgsl_issueibcmds(dev_priv->device, param, result);
Wei Zouc8c01632012-03-24 17:27:26 -07001080
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001081free_ibdesc:
1082 kfree(ibdesc);
1083done:
1084
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001085 return result;
1086}
1087
Carter Cooper7e7f02e2012-02-15 09:36:31 -07001088static long _cmdstream_readtimestamp(struct kgsl_device_private *dev_priv,
1089 struct kgsl_context *context, unsigned int type,
1090 unsigned int *timestamp)
1091{
1092 *timestamp = dev_priv->device->ftbl->readtimestamp(dev_priv->device,
1093 context, type);
1094
1095 trace_kgsl_readtimestamp(dev_priv->device,
1096 context ? context->id : KGSL_MEMSTORE_GLOBAL,
1097 type, *timestamp);
1098
1099 return 0;
1100}
1101
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001102static long kgsl_ioctl_cmdstream_readtimestamp(struct kgsl_device_private
1103 *dev_priv, unsigned int cmd,
1104 void *data)
1105{
1106 struct kgsl_cmdstream_readtimestamp *param = data;
1107
Carter Cooper7e7f02e2012-02-15 09:36:31 -07001108 return _cmdstream_readtimestamp(dev_priv, NULL,
1109 param->type, &param->timestamp);
1110}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001111
Carter Cooper7e7f02e2012-02-15 09:36:31 -07001112static long kgsl_ioctl_cmdstream_readtimestamp_ctxtid(struct kgsl_device_private
1113 *dev_priv, unsigned int cmd,
1114 void *data)
1115{
1116 struct kgsl_cmdstream_readtimestamp_ctxtid *param = data;
1117 struct kgsl_context *context;
Norman Geed7402ff2011-10-28 08:51:11 -06001118
Carter Cooper7e7f02e2012-02-15 09:36:31 -07001119 context = kgsl_find_context(dev_priv, param->context_id);
1120 if (context == NULL) {
1121 KGSL_DRV_ERR(dev_priv->device, "invalid context_id %d\n",
1122 param->context_id);
1123 return -EINVAL;
1124 }
1125
1126 return _cmdstream_readtimestamp(dev_priv, context,
1127 param->type, &param->timestamp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001128}
1129
Jeremy Gebbenc81a3c62012-02-07 16:10:23 -07001130static void kgsl_freemem_event_cb(struct kgsl_device *device,
Carter Cooper7e7f02e2012-02-15 09:36:31 -07001131 void *priv, u32 id, u32 timestamp)
Jeremy Gebbenc81a3c62012-02-07 16:10:23 -07001132{
1133 struct kgsl_mem_entry *entry = priv;
1134 spin_lock(&entry->priv->mem_lock);
Jordan Crousec9559e42012-04-05 16:55:56 -06001135 rb_erase(&entry->node, &entry->priv->mem_rb);
Jeremy Gebbenc81a3c62012-02-07 16:10:23 -07001136 spin_unlock(&entry->priv->mem_lock);
Carter Cooper7e7f02e2012-02-15 09:36:31 -07001137 trace_kgsl_mem_timestamp_free(entry, id, timestamp);
Jordan Crouse00714012012-03-16 14:53:40 -06001138 kgsl_mem_entry_detach_process(entry);
Jeremy Gebbenc81a3c62012-02-07 16:10:23 -07001139}
1140
Carter Cooper7e7f02e2012-02-15 09:36:31 -07001141static long _cmdstream_freememontimestamp(struct kgsl_device_private *dev_priv,
1142 unsigned int gpuaddr, struct kgsl_context *context,
1143 unsigned int timestamp, unsigned int type)
1144{
1145 int result = 0;
1146 struct kgsl_mem_entry *entry = NULL;
1147 struct kgsl_device *device = dev_priv->device;
1148 unsigned int cur;
1149 unsigned int context_id = context ? context->id : KGSL_MEMSTORE_GLOBAL;
1150
1151 spin_lock(&dev_priv->process_priv->mem_lock);
1152 entry = kgsl_sharedmem_find(dev_priv->process_priv, gpuaddr);
1153 spin_unlock(&dev_priv->process_priv->mem_lock);
1154
1155 if (entry) {
1156 cur = device->ftbl->readtimestamp(device, context,
1157 KGSL_TIMESTAMP_RETIRED);
1158
1159 trace_kgsl_mem_timestamp_queue(entry, context_id, cur);
1160 result = kgsl_add_event(dev_priv->device, context_id,
1161 timestamp, kgsl_freemem_event_cb,
1162 entry, dev_priv);
1163 } else {
1164 KGSL_DRV_ERR(dev_priv->device,
1165 "invalid gpuaddr %08x\n", gpuaddr);
1166 result = -EINVAL;
1167 }
1168
1169 return result;
1170}
1171
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001172static long kgsl_ioctl_cmdstream_freememontimestamp(struct kgsl_device_private
1173 *dev_priv, unsigned int cmd,
1174 void *data)
1175{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001176 struct kgsl_cmdstream_freememontimestamp *param = data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001177
Carter Cooper7e7f02e2012-02-15 09:36:31 -07001178 return _cmdstream_freememontimestamp(dev_priv, param->gpuaddr,
1179 NULL, param->timestamp, param->type);
1180}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001181
Carter Cooper7e7f02e2012-02-15 09:36:31 -07001182static long kgsl_ioctl_cmdstream_freememontimestamp_ctxtid(
1183 struct kgsl_device_private
1184 *dev_priv, unsigned int cmd,
1185 void *data)
1186{
1187 struct kgsl_cmdstream_freememontimestamp_ctxtid *param = data;
1188 struct kgsl_context *context;
Jeremy Gebbena5859272012-03-01 12:46:28 -07001189
Carter Cooper7e7f02e2012-02-15 09:36:31 -07001190 context = kgsl_find_context(dev_priv, param->context_id);
1191 if (context == NULL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001192 KGSL_DRV_ERR(dev_priv->device,
Carter Cooper7e7f02e2012-02-15 09:36:31 -07001193 "invalid drawctxt context_id %d\n", param->context_id);
1194 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001195 }
1196
Carter Cooper7e7f02e2012-02-15 09:36:31 -07001197 return _cmdstream_freememontimestamp(dev_priv, param->gpuaddr,
1198 context, param->timestamp, param->type);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001199}
1200
1201static long kgsl_ioctl_drawctxt_create(struct kgsl_device_private *dev_priv,
1202 unsigned int cmd, void *data)
1203{
1204 int result = 0;
1205 struct kgsl_drawctxt_create *param = data;
1206 struct kgsl_context *context = NULL;
1207
1208 context = kgsl_create_context(dev_priv);
1209
1210 if (context == NULL) {
1211 result = -ENOMEM;
1212 goto done;
1213 }
1214
1215 if (dev_priv->device->ftbl->drawctxt_create)
1216 result = dev_priv->device->ftbl->drawctxt_create(
1217 dev_priv->device, dev_priv->process_priv->pagetable,
1218 context, param->flags);
1219
1220 param->drawctxt_id = context->id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001221done:
1222 if (result && context)
1223 kgsl_destroy_context(dev_priv, context);
1224
1225 return result;
1226}
1227
1228static long kgsl_ioctl_drawctxt_destroy(struct kgsl_device_private *dev_priv,
1229 unsigned int cmd, void *data)
1230{
1231 int result = 0;
1232 struct kgsl_drawctxt_destroy *param = data;
1233 struct kgsl_context *context;
1234
1235 context = kgsl_find_context(dev_priv, param->drawctxt_id);
1236
1237 if (context == NULL) {
1238 result = -EINVAL;
1239 goto done;
1240 }
1241
1242 if (dev_priv->device->ftbl->drawctxt_destroy)
1243 dev_priv->device->ftbl->drawctxt_destroy(dev_priv->device,
1244 context);
1245
1246 kgsl_destroy_context(dev_priv, context);
1247
1248done:
1249 return result;
1250}
1251
1252static long kgsl_ioctl_sharedmem_free(struct kgsl_device_private *dev_priv,
1253 unsigned int cmd, void *data)
1254{
1255 int result = 0;
1256 struct kgsl_sharedmem_free *param = data;
1257 struct kgsl_process_private *private = dev_priv->process_priv;
1258 struct kgsl_mem_entry *entry = NULL;
1259
1260 spin_lock(&private->mem_lock);
1261 entry = kgsl_sharedmem_find(private, param->gpuaddr);
1262 if (entry)
Jordan Crousec9559e42012-04-05 16:55:56 -06001263 rb_erase(&entry->node, &private->mem_rb);
1264
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001265 spin_unlock(&private->mem_lock);
1266
1267 if (entry) {
Jeremy Gebbena5859272012-03-01 12:46:28 -07001268 trace_kgsl_mem_free(entry);
Jordan Crouse00714012012-03-16 14:53:40 -06001269 kgsl_mem_entry_detach_process(entry);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001270 } else {
1271 KGSL_CORE_ERR("invalid gpuaddr %08x\n", param->gpuaddr);
1272 result = -EINVAL;
1273 }
1274
1275 return result;
1276}
1277
1278static struct vm_area_struct *kgsl_get_vma_from_start_addr(unsigned int addr)
1279{
1280 struct vm_area_struct *vma;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001281
1282 down_read(&current->mm->mmap_sem);
1283 vma = find_vma(current->mm, addr);
1284 up_read(&current->mm->mmap_sem);
Jordan Crouse2c542b62011-07-26 08:30:20 -06001285 if (!vma)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001286 KGSL_CORE_ERR("find_vma(%x) failed\n", addr);
Jordan Crouse2c542b62011-07-26 08:30:20 -06001287
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001288 return vma;
1289}
1290
1291static long
1292kgsl_ioctl_sharedmem_from_vmalloc(struct kgsl_device_private *dev_priv,
1293 unsigned int cmd, void *data)
1294{
1295 int result = 0, len = 0;
1296 struct kgsl_process_private *private = dev_priv->process_priv;
1297 struct kgsl_sharedmem_from_vmalloc *param = data;
1298 struct kgsl_mem_entry *entry = NULL;
1299 struct vm_area_struct *vma;
1300
Harsh Vardhan Dwivedia9eb7cb2012-03-26 15:21:38 -06001301 KGSL_DEV_ERR_ONCE(dev_priv->device, "IOCTL_KGSL_SHAREDMEM_FROM_VMALLOC"
1302 " is deprecated\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001303 if (!kgsl_mmu_enabled())
1304 return -ENODEV;
1305
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001306 if (!param->hostptr) {
1307 KGSL_CORE_ERR("invalid hostptr %x\n", param->hostptr);
1308 result = -EINVAL;
1309 goto error;
1310 }
1311
1312 vma = kgsl_get_vma_from_start_addr(param->hostptr);
1313 if (!vma) {
1314 result = -EINVAL;
1315 goto error;
1316 }
Jordan Crouse2c542b62011-07-26 08:30:20 -06001317
1318 /*
1319 * If the user specified a length, use it, otherwise try to
1320 * infer the length if the vma region
1321 */
1322 if (param->gpuaddr != 0) {
1323 len = param->gpuaddr;
1324 } else {
1325 /*
1326 * For this to work, we have to assume the VMA region is only
1327 * for this single allocation. If it isn't, then bail out
1328 */
1329 if (vma->vm_pgoff || (param->hostptr != vma->vm_start)) {
1330 KGSL_CORE_ERR("VMA region does not match hostaddr\n");
1331 result = -EINVAL;
1332 goto error;
1333 }
1334
1335 len = vma->vm_end - vma->vm_start;
1336 }
1337
1338 /* Make sure it fits */
1339 if (len == 0 || param->hostptr + len > vma->vm_end) {
1340 KGSL_CORE_ERR("Invalid memory allocation length %d\n", len);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001341 result = -EINVAL;
1342 goto error;
1343 }
1344
1345 entry = kgsl_mem_entry_create();
1346 if (entry == NULL) {
1347 result = -ENOMEM;
1348 goto error;
1349 }
1350
Harsh Vardhan Dwivedif99c2632012-03-15 14:17:11 -06001351 result = kgsl_sharedmem_page_alloc_user(&entry->memdesc,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001352 private->pagetable, len,
1353 param->flags);
1354 if (result != 0)
1355 goto error_free_entry;
1356
1357 vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
1358
Harsh Vardhan Dwivedi8cb835b2012-03-29 17:23:11 -06001359 result = kgsl_sharedmem_map_vma(vma, &entry->memdesc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001360 if (result) {
Harsh Vardhan Dwivedi8cb835b2012-03-29 17:23:11 -06001361 KGSL_CORE_ERR("kgsl_sharedmem_map_vma failed: %d\n", result);
Harsh Vardhan Dwivedif99c2632012-03-15 14:17:11 -06001362 goto error_free_alloc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001363 }
1364
1365 param->gpuaddr = entry->memdesc.gpuaddr;
1366
Jordan Crouse1b897cf2011-10-12 16:57:48 -06001367 entry->memtype = KGSL_MEM_ENTRY_KERNEL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001368
1369 kgsl_mem_entry_attach_process(entry, private);
1370
Jeremy Gebbena5859272012-03-01 12:46:28 -07001371 trace_kgsl_mem_alloc(entry);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001372 /* Process specific statistics */
Jordan Crouse1b897cf2011-10-12 16:57:48 -06001373 kgsl_process_add_stats(private, entry->memtype, len);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001374
1375 kgsl_check_idle(dev_priv->device);
1376 return 0;
1377
Harsh Vardhan Dwivedif99c2632012-03-15 14:17:11 -06001378error_free_alloc:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001379 kgsl_sharedmem_free(&entry->memdesc);
1380
1381error_free_entry:
1382 kfree(entry);
1383
1384error:
1385 kgsl_check_idle(dev_priv->device);
1386 return result;
1387}
1388
1389static inline int _check_region(unsigned long start, unsigned long size,
1390 uint64_t len)
1391{
1392 uint64_t end = ((uint64_t) start) + size;
1393 return (end > len);
1394}
1395
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001396static int kgsl_get_phys_file(int fd, unsigned long *start, unsigned long *len,
1397 unsigned long *vstart, struct file **filep)
1398{
1399 struct file *fbfile;
1400 int ret = 0;
1401 dev_t rdev;
1402 struct fb_info *info;
1403
1404 *filep = NULL;
Jordan Crousefd978432011-09-02 14:34:32 -06001405#ifdef CONFIG_ANDROID_PMEM
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001406 if (!get_pmem_file(fd, start, vstart, len, filep))
1407 return 0;
Jordan Crousefd978432011-09-02 14:34:32 -06001408#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001409
1410 fbfile = fget(fd);
1411 if (fbfile == NULL) {
1412 KGSL_CORE_ERR("fget_light failed\n");
1413 return -1;
1414 }
1415
1416 rdev = fbfile->f_dentry->d_inode->i_rdev;
1417 info = MAJOR(rdev) == FB_MAJOR ? registered_fb[MINOR(rdev)] : NULL;
1418 if (info) {
1419 *start = info->fix.smem_start;
1420 *len = info->fix.smem_len;
1421 *vstart = (unsigned long)__va(info->fix.smem_start);
1422 ret = 0;
1423 } else {
1424 KGSL_CORE_ERR("framebuffer minor %d not found\n",
1425 MINOR(rdev));
1426 ret = -1;
1427 }
1428
1429 fput(fbfile);
1430
1431 return ret;
1432}
1433
1434static int kgsl_setup_phys_file(struct kgsl_mem_entry *entry,
1435 struct kgsl_pagetable *pagetable,
1436 unsigned int fd, unsigned int offset,
1437 size_t size)
1438{
1439 int ret;
1440 unsigned long phys, virt, len;
1441 struct file *filep;
1442
1443 ret = kgsl_get_phys_file(fd, &phys, &len, &virt, &filep);
1444 if (ret)
1445 return ret;
1446
Wei Zou4061c0b2011-07-08 10:24:22 -07001447 if (phys == 0) {
1448 ret = -EINVAL;
1449 goto err;
1450 }
1451
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001452 if (offset >= len) {
1453 ret = -EINVAL;
1454 goto err;
1455 }
1456
1457 if (size == 0)
1458 size = len;
1459
1460 /* Adjust the size of the region to account for the offset */
1461 size += offset & ~PAGE_MASK;
1462
1463 size = ALIGN(size, PAGE_SIZE);
1464
1465 if (_check_region(offset & PAGE_MASK, size, len)) {
1466 KGSL_CORE_ERR("Offset (%ld) + size (%d) is larger"
1467 "than pmem region length %ld\n",
1468 offset & PAGE_MASK, size, len);
1469 ret = -EINVAL;
1470 goto err;
1471
1472 }
1473
Jordan Crouse1b897cf2011-10-12 16:57:48 -06001474 entry->priv_data = filep;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001475
1476 entry->memdesc.pagetable = pagetable;
1477 entry->memdesc.size = size;
1478 entry->memdesc.physaddr = phys + (offset & PAGE_MASK);
1479 entry->memdesc.hostptr = (void *) (virt + (offset & PAGE_MASK));
Jordan Croused17e9aa2011-10-12 16:57:48 -06001480
1481 ret = memdesc_sg_phys(&entry->memdesc,
1482 phys + (offset & PAGE_MASK), size);
1483 if (ret)
1484 goto err;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001485
1486 return 0;
1487err:
Jordan Crousefd978432011-09-02 14:34:32 -06001488#ifdef CONFIG_ANDROID_PMEM
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001489 put_pmem_file(filep);
Jordan Crousefd978432011-09-02 14:34:32 -06001490#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001491 return ret;
1492}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001493
Jordan Croused17e9aa2011-10-12 16:57:48 -06001494static int memdesc_sg_virt(struct kgsl_memdesc *memdesc,
1495 void *addr, int size)
1496{
1497 int i;
1498 int sglen = PAGE_ALIGN(size) / PAGE_SIZE;
1499 unsigned long paddr = (unsigned long) addr;
1500
Jordan Crousea652a072012-04-06 16:26:33 -06001501 memdesc->sg = kgsl_sg_alloc(sglen);
1502
Jordan Croused17e9aa2011-10-12 16:57:48 -06001503 if (memdesc->sg == NULL)
1504 return -ENOMEM;
1505
1506 memdesc->sglen = sglen;
1507 sg_init_table(memdesc->sg, sglen);
1508
1509 spin_lock(&current->mm->page_table_lock);
1510
1511 for (i = 0; i < sglen; i++, paddr += PAGE_SIZE) {
1512 struct page *page;
1513 pmd_t *ppmd;
1514 pte_t *ppte;
1515 pgd_t *ppgd = pgd_offset(current->mm, paddr);
1516
1517 if (pgd_none(*ppgd) || pgd_bad(*ppgd))
1518 goto err;
1519
1520 ppmd = pmd_offset(ppgd, paddr);
1521 if (pmd_none(*ppmd) || pmd_bad(*ppmd))
1522 goto err;
1523
1524 ppte = pte_offset_map(ppmd, paddr);
1525 if (ppte == NULL)
1526 goto err;
1527
1528 page = pfn_to_page(pte_pfn(*ppte));
1529 if (!page)
1530 goto err;
1531
1532 sg_set_page(&memdesc->sg[i], page, PAGE_SIZE, 0);
1533 pte_unmap(ppte);
1534 }
1535
1536 spin_unlock(&current->mm->page_table_lock);
1537
1538 return 0;
1539
1540err:
1541 spin_unlock(&current->mm->page_table_lock);
Jordan Crousea652a072012-04-06 16:26:33 -06001542 kgsl_sg_free(memdesc->sg, sglen);
Jordan Croused17e9aa2011-10-12 16:57:48 -06001543 memdesc->sg = NULL;
1544
1545 return -EINVAL;
1546}
1547
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001548static int kgsl_setup_hostptr(struct kgsl_mem_entry *entry,
1549 struct kgsl_pagetable *pagetable,
1550 void *hostptr, unsigned int offset,
1551 size_t size)
1552{
1553 struct vm_area_struct *vma;
1554 unsigned int len;
1555
1556 down_read(&current->mm->mmap_sem);
1557 vma = find_vma(current->mm, (unsigned int) hostptr);
1558 up_read(&current->mm->mmap_sem);
1559
1560 if (!vma) {
1561 KGSL_CORE_ERR("find_vma(%p) failed\n", hostptr);
1562 return -EINVAL;
1563 }
1564
1565 /* We don't necessarily start at vma->vm_start */
1566 len = vma->vm_end - (unsigned long) hostptr;
1567
1568 if (offset >= len)
1569 return -EINVAL;
1570
1571 if (!KGSL_IS_PAGE_ALIGNED((unsigned long) hostptr) ||
1572 !KGSL_IS_PAGE_ALIGNED(len)) {
1573 KGSL_CORE_ERR("user address len(%u)"
1574 "and start(%p) must be page"
1575 "aligned\n", len, hostptr);
1576 return -EINVAL;
1577 }
1578
1579 if (size == 0)
1580 size = len;
1581
1582 /* Adjust the size of the region to account for the offset */
1583 size += offset & ~PAGE_MASK;
1584
1585 size = ALIGN(size, PAGE_SIZE);
1586
1587 if (_check_region(offset & PAGE_MASK, size, len)) {
1588 KGSL_CORE_ERR("Offset (%ld) + size (%d) is larger"
1589 "than region length %d\n",
1590 offset & PAGE_MASK, size, len);
1591 return -EINVAL;
1592 }
1593
1594 entry->memdesc.pagetable = pagetable;
1595 entry->memdesc.size = size;
1596 entry->memdesc.hostptr = hostptr + (offset & PAGE_MASK);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001597
Jordan Croused17e9aa2011-10-12 16:57:48 -06001598 return memdesc_sg_virt(&entry->memdesc,
1599 hostptr + (offset & PAGE_MASK), size);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001600}
1601
1602#ifdef CONFIG_ASHMEM
1603static int kgsl_setup_ashmem(struct kgsl_mem_entry *entry,
1604 struct kgsl_pagetable *pagetable,
1605 int fd, void *hostptr, size_t size)
1606{
1607 int ret;
1608 struct vm_area_struct *vma;
1609 struct file *filep, *vmfile;
1610 unsigned long len;
Jordan Crouse2c542b62011-07-26 08:30:20 -06001611 unsigned int hostaddr = (unsigned int) hostptr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001612
Jordan Crouse2c542b62011-07-26 08:30:20 -06001613 vma = kgsl_get_vma_from_start_addr(hostaddr);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001614 if (vma == NULL)
1615 return -EINVAL;
1616
Jordan Crouse2c542b62011-07-26 08:30:20 -06001617 if (vma->vm_pgoff || vma->vm_start != hostaddr) {
1618 KGSL_CORE_ERR("Invalid vma region\n");
1619 return -EINVAL;
1620 }
1621
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001622 len = vma->vm_end - vma->vm_start;
1623
1624 if (size == 0)
1625 size = len;
1626
1627 if (size != len) {
1628 KGSL_CORE_ERR("Invalid size %d for vma region %p\n",
1629 size, hostptr);
1630 return -EINVAL;
1631 }
1632
1633 ret = get_ashmem_file(fd, &filep, &vmfile, &len);
1634
1635 if (ret) {
1636 KGSL_CORE_ERR("get_ashmem_file failed\n");
1637 return ret;
1638 }
1639
1640 if (vmfile != vma->vm_file) {
1641 KGSL_CORE_ERR("ashmem shmem file does not match vma\n");
1642 ret = -EINVAL;
1643 goto err;
1644 }
1645
Jordan Crouse1b897cf2011-10-12 16:57:48 -06001646 entry->priv_data = filep;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001647 entry->memdesc.pagetable = pagetable;
1648 entry->memdesc.size = ALIGN(size, PAGE_SIZE);
1649 entry->memdesc.hostptr = hostptr;
Jordan Croused17e9aa2011-10-12 16:57:48 -06001650
1651 ret = memdesc_sg_virt(&entry->memdesc, hostptr, size);
1652 if (ret)
1653 goto err;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001654
1655 return 0;
1656
1657err:
1658 put_ashmem_file(filep);
1659 return ret;
1660}
1661#else
1662static int kgsl_setup_ashmem(struct kgsl_mem_entry *entry,
1663 struct kgsl_pagetable *pagetable,
1664 int fd, void *hostptr, size_t size)
1665{
1666 return -EINVAL;
1667}
1668#endif
1669
Jordan Crouse8eab35a2011-10-12 16:57:48 -06001670static int kgsl_setup_ion(struct kgsl_mem_entry *entry,
1671 struct kgsl_pagetable *pagetable, int fd)
1672{
1673 struct ion_handle *handle;
1674 struct scatterlist *s;
1675 unsigned long flags;
1676
Harsh Vardhan Dwivedif48af7f2012-04-13 12:50:44 -06001677 if (IS_ERR_OR_NULL(kgsl_ion_client))
1678 return -ENODEV;
Jordan Crouse8eab35a2011-10-12 16:57:48 -06001679
1680 handle = ion_import_fd(kgsl_ion_client, fd);
1681 if (IS_ERR_OR_NULL(handle))
1682 return PTR_ERR(handle);
1683
1684 entry->memtype = KGSL_MEM_ENTRY_ION;
1685 entry->priv_data = handle;
1686 entry->memdesc.pagetable = pagetable;
1687 entry->memdesc.size = 0;
1688
1689 if (ion_handle_get_flags(kgsl_ion_client, handle, &flags))
1690 goto err;
1691
1692 entry->memdesc.sg = ion_map_dma(kgsl_ion_client, handle, flags);
1693
1694 if (IS_ERR_OR_NULL(entry->memdesc.sg))
1695 goto err;
1696
1697 /* Calculate the size of the memdesc from the sglist */
1698
1699 entry->memdesc.sglen = 0;
1700
1701 for (s = entry->memdesc.sg; s != NULL; s = sg_next(s)) {
1702 entry->memdesc.size += s->length;
1703 entry->memdesc.sglen++;
1704 }
1705
1706 return 0;
1707err:
1708 ion_free(kgsl_ion_client, handle);
1709 return -ENOMEM;
1710}
1711
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001712static long kgsl_ioctl_map_user_mem(struct kgsl_device_private *dev_priv,
1713 unsigned int cmd, void *data)
1714{
1715 int result = -EINVAL;
1716 struct kgsl_map_user_mem *param = data;
1717 struct kgsl_mem_entry *entry = NULL;
1718 struct kgsl_process_private *private = dev_priv->process_priv;
Jason848741a2011-07-12 10:24:25 -07001719 enum kgsl_user_mem_type memtype;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001720
1721 entry = kgsl_mem_entry_create();
1722
1723 if (entry == NULL)
1724 return -ENOMEM;
1725
Jason848741a2011-07-12 10:24:25 -07001726 if (_IOC_SIZE(cmd) == sizeof(struct kgsl_sharedmem_from_pmem))
1727 memtype = KGSL_USER_MEM_TYPE_PMEM;
1728 else
1729 memtype = param->memtype;
1730
1731 switch (memtype) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001732 case KGSL_USER_MEM_TYPE_PMEM:
1733 if (param->fd == 0 || param->len == 0)
1734 break;
1735
1736 result = kgsl_setup_phys_file(entry, private->pagetable,
1737 param->fd, param->offset,
1738 param->len);
Jordan Crouse1b897cf2011-10-12 16:57:48 -06001739 entry->memtype = KGSL_MEM_ENTRY_PMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001740 break;
1741
1742 case KGSL_USER_MEM_TYPE_ADDR:
Harsh Vardhan Dwivedia9eb7cb2012-03-26 15:21:38 -06001743 KGSL_DEV_ERR_ONCE(dev_priv->device, "User mem type "
1744 "KGSL_USER_MEM_TYPE_ADDR is deprecated\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001745 if (!kgsl_mmu_enabled()) {
1746 KGSL_DRV_ERR(dev_priv->device,
1747 "Cannot map paged memory with the "
1748 "MMU disabled\n");
1749 break;
1750 }
1751
1752 if (param->hostptr == 0)
1753 break;
1754
1755 result = kgsl_setup_hostptr(entry, private->pagetable,
1756 (void *) param->hostptr,
1757 param->offset, param->len);
Jordan Crouse1b897cf2011-10-12 16:57:48 -06001758 entry->memtype = KGSL_MEM_ENTRY_USER;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001759 break;
1760
1761 case KGSL_USER_MEM_TYPE_ASHMEM:
1762 if (!kgsl_mmu_enabled()) {
1763 KGSL_DRV_ERR(dev_priv->device,
1764 "Cannot map paged memory with the "
1765 "MMU disabled\n");
1766 break;
1767 }
1768
1769 if (param->hostptr == 0)
1770 break;
1771
1772 result = kgsl_setup_ashmem(entry, private->pagetable,
1773 param->fd, (void *) param->hostptr,
1774 param->len);
Jordan Crouse1b897cf2011-10-12 16:57:48 -06001775
1776 entry->memtype = KGSL_MEM_ENTRY_ASHMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001777 break;
Jordan Crouse8eab35a2011-10-12 16:57:48 -06001778 case KGSL_USER_MEM_TYPE_ION:
1779 result = kgsl_setup_ion(entry, private->pagetable,
1780 param->fd);
1781 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001782 default:
Jason848741a2011-07-12 10:24:25 -07001783 KGSL_CORE_ERR("Invalid memory type: %x\n", memtype);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001784 break;
1785 }
1786
1787 if (result)
1788 goto error;
1789
1790 result = kgsl_mmu_map(private->pagetable,
1791 &entry->memdesc,
1792 GSL_PT_PAGE_RV | GSL_PT_PAGE_WV);
1793
1794 if (result)
1795 goto error_put_file_ptr;
1796
1797 /* Adjust the returned value for a non 4k aligned offset */
1798 param->gpuaddr = entry->memdesc.gpuaddr + (param->offset & ~PAGE_MASK);
1799
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001800 KGSL_STATS_ADD(param->len, kgsl_driver.stats.mapped,
Jordan Crouse1b897cf2011-10-12 16:57:48 -06001801 kgsl_driver.stats.mapped_max);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001802
Jordan Crouse1b897cf2011-10-12 16:57:48 -06001803 kgsl_process_add_stats(private, entry->memtype, param->len);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001804
1805 kgsl_mem_entry_attach_process(entry, private);
Jeremy Gebbena5859272012-03-01 12:46:28 -07001806 trace_kgsl_mem_map(entry, param->fd);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001807
1808 kgsl_check_idle(dev_priv->device);
1809 return result;
1810
1811 error_put_file_ptr:
Jordan Crouse1b897cf2011-10-12 16:57:48 -06001812 if (entry->priv_data)
1813 fput(entry->priv_data);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001814
1815error:
1816 kfree(entry);
1817 kgsl_check_idle(dev_priv->device);
1818 return result;
1819}
1820
1821/*This function flushes a graphics memory allocation from CPU cache
1822 *when caching is enabled with MMU*/
1823static long
1824kgsl_ioctl_sharedmem_flush_cache(struct kgsl_device_private *dev_priv,
1825 unsigned int cmd, void *data)
1826{
1827 int result = 0;
1828 struct kgsl_mem_entry *entry;
1829 struct kgsl_sharedmem_free *param = data;
1830 struct kgsl_process_private *private = dev_priv->process_priv;
1831
1832 spin_lock(&private->mem_lock);
1833 entry = kgsl_sharedmem_find(private, param->gpuaddr);
1834 if (!entry) {
1835 KGSL_CORE_ERR("invalid gpuaddr %08x\n", param->gpuaddr);
1836 result = -EINVAL;
Jeremy Gebben690f9d12011-08-08 16:33:49 -06001837 goto done;
1838 }
Jeremy Gebben690f9d12011-08-08 16:33:49 -06001839 if (!entry->memdesc.hostptr) {
1840 KGSL_CORE_ERR("invalid hostptr with gpuaddr %08x\n",
1841 param->gpuaddr);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001842 goto done;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001843 }
Jeremy Gebben690f9d12011-08-08 16:33:49 -06001844
1845 kgsl_cache_range_op(&entry->memdesc, KGSL_CACHE_OP_CLEAN);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001846done:
Jeremy Gebben690f9d12011-08-08 16:33:49 -06001847 spin_unlock(&private->mem_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001848 return result;
1849}
1850
1851static long
1852kgsl_ioctl_gpumem_alloc(struct kgsl_device_private *dev_priv,
1853 unsigned int cmd, void *data)
1854{
1855 struct kgsl_process_private *private = dev_priv->process_priv;
1856 struct kgsl_gpumem_alloc *param = data;
1857 struct kgsl_mem_entry *entry;
1858 int result;
1859
1860 entry = kgsl_mem_entry_create();
1861 if (entry == NULL)
1862 return -ENOMEM;
1863
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001864 result = kgsl_allocate_user(&entry->memdesc, private->pagetable,
1865 param->size, param->flags);
1866
1867 if (result == 0) {
Jordan Crouse1b897cf2011-10-12 16:57:48 -06001868 entry->memtype = KGSL_MEM_ENTRY_KERNEL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001869 kgsl_mem_entry_attach_process(entry, private);
1870 param->gpuaddr = entry->memdesc.gpuaddr;
1871
Jordan Crouse1b897cf2011-10-12 16:57:48 -06001872 kgsl_process_add_stats(private, entry->memtype, param->size);
Jeremy Gebbena5859272012-03-01 12:46:28 -07001873 trace_kgsl_mem_alloc(entry);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001874 } else
1875 kfree(entry);
1876
1877 kgsl_check_idle(dev_priv->device);
1878 return result;
1879}
Jeremy Gebbena7423e42011-04-18 15:11:21 -06001880static long kgsl_ioctl_cff_syncmem(struct kgsl_device_private *dev_priv,
1881 unsigned int cmd, void *data)
1882{
1883 int result = 0;
1884 struct kgsl_cff_syncmem *param = data;
1885 struct kgsl_process_private *private = dev_priv->process_priv;
1886 struct kgsl_mem_entry *entry = NULL;
1887
1888 spin_lock(&private->mem_lock);
1889 entry = kgsl_sharedmem_find_region(private, param->gpuaddr, param->len);
1890 if (entry)
1891 kgsl_cffdump_syncmem(dev_priv, &entry->memdesc, param->gpuaddr,
1892 param->len, true);
1893 else
1894 result = -EINVAL;
1895 spin_unlock(&private->mem_lock);
1896 return result;
1897}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001898
Sushmita Susheelendra41f8fa32011-05-11 17:15:58 -06001899static long kgsl_ioctl_cff_user_event(struct kgsl_device_private *dev_priv,
1900 unsigned int cmd, void *data)
1901{
1902 int result = 0;
1903 struct kgsl_cff_user_event *param = data;
1904
1905 kgsl_cffdump_user_event(param->cff_opcode, param->op1, param->op2,
1906 param->op3, param->op4, param->op5);
1907
1908 return result;
1909}
1910
Jordan Croused4bc9d22011-11-17 13:39:21 -07001911#ifdef CONFIG_GENLOCK
1912struct kgsl_genlock_event_priv {
1913 struct genlock_handle *handle;
1914 struct genlock *lock;
1915};
1916
1917/**
1918 * kgsl_genlock_event_cb - Event callback for a genlock timestamp event
1919 * @device - The KGSL device that expired the timestamp
1920 * @priv - private data for the event
Carter Cooper7e7f02e2012-02-15 09:36:31 -07001921 * @context_id - the context id that goes with the timestamp
Jordan Croused4bc9d22011-11-17 13:39:21 -07001922 * @timestamp - the timestamp that triggered the event
1923 *
1924 * Release a genlock lock following the expiration of a timestamp
1925 */
1926
1927static void kgsl_genlock_event_cb(struct kgsl_device *device,
Carter Cooper7e7f02e2012-02-15 09:36:31 -07001928 void *priv, u32 context_id, u32 timestamp)
Jordan Croused4bc9d22011-11-17 13:39:21 -07001929{
1930 struct kgsl_genlock_event_priv *ev = priv;
1931 int ret;
1932
1933 ret = genlock_lock(ev->handle, GENLOCK_UNLOCK, 0, 0);
1934 if (ret)
1935 KGSL_CORE_ERR("Error while unlocking genlock: %d\n", ret);
1936
1937 genlock_put_handle(ev->handle);
1938
1939 kfree(ev);
1940}
1941
1942/**
1943 * kgsl_add_genlock-event - Create a new genlock event
1944 * @device - KGSL device to create the event on
1945 * @timestamp - Timestamp to trigger the event
1946 * @data - User space buffer containing struct kgsl_genlock_event_priv
1947 * @len - length of the userspace buffer
Jeremy Gebbenfd87f9a2012-02-10 07:06:09 -07001948 * @owner - driver instance that owns this event
Jordan Croused4bc9d22011-11-17 13:39:21 -07001949 * @returns 0 on success or error code on error
1950 *
1951 * Attack to a genlock handle and register an event to release the
1952 * genlock lock when the timestamp expires
1953 */
1954
1955static int kgsl_add_genlock_event(struct kgsl_device *device,
Carter Cooper7e7f02e2012-02-15 09:36:31 -07001956 u32 context_id, u32 timestamp, void __user *data, int len,
Jeremy Gebbenfd87f9a2012-02-10 07:06:09 -07001957 struct kgsl_device_private *owner)
Jordan Croused4bc9d22011-11-17 13:39:21 -07001958{
1959 struct kgsl_genlock_event_priv *event;
1960 struct kgsl_timestamp_event_genlock priv;
1961 int ret;
1962
1963 if (len != sizeof(priv))
1964 return -EINVAL;
1965
1966 if (copy_from_user(&priv, data, sizeof(priv)))
1967 return -EFAULT;
1968
1969 event = kzalloc(sizeof(*event), GFP_KERNEL);
1970
1971 if (event == NULL)
1972 return -ENOMEM;
1973
1974 event->handle = genlock_get_handle_fd(priv.handle);
1975
1976 if (IS_ERR(event->handle)) {
1977 int ret = PTR_ERR(event->handle);
1978 kfree(event);
1979 return ret;
1980 }
1981
Carter Cooper7e7f02e2012-02-15 09:36:31 -07001982 ret = kgsl_add_event(device, context_id, timestamp,
1983 kgsl_genlock_event_cb, event, owner);
Jordan Croused4bc9d22011-11-17 13:39:21 -07001984 if (ret)
1985 kfree(event);
1986
1987 return ret;
1988}
1989#else
1990static long kgsl_add_genlock_event(struct kgsl_device *device,
Carter Cooper7e7f02e2012-02-15 09:36:31 -07001991 u32 context_id, u32 timestamp, void __user *data, int len,
Jeremy Gebbenfd87f9a2012-02-10 07:06:09 -07001992 struct kgsl_device_private *owner)
Jordan Croused4bc9d22011-11-17 13:39:21 -07001993{
1994 return -EINVAL;
1995}
1996#endif
1997
1998/**
1999 * kgsl_ioctl_timestamp_event - Register a new timestamp event from userspace
2000 * @dev_priv - pointer to the private device structure
2001 * @cmd - the ioctl cmd passed from kgsl_ioctl
2002 * @data - the user data buffer from kgsl_ioctl
2003 * @returns 0 on success or error code on failure
2004 */
2005
2006static long kgsl_ioctl_timestamp_event(struct kgsl_device_private *dev_priv,
2007 unsigned int cmd, void *data)
2008{
2009 struct kgsl_timestamp_event *param = data;
2010 int ret;
2011
2012 switch (param->type) {
2013 case KGSL_TIMESTAMP_EVENT_GENLOCK:
2014 ret = kgsl_add_genlock_event(dev_priv->device,
Carter Cooper7e7f02e2012-02-15 09:36:31 -07002015 param->context_id, param->timestamp, param->priv,
2016 param->len, dev_priv);
Jordan Croused4bc9d22011-11-17 13:39:21 -07002017 break;
2018 default:
2019 ret = -EINVAL;
2020 }
2021
2022 return ret;
2023}
2024
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002025typedef long (*kgsl_ioctl_func_t)(struct kgsl_device_private *,
2026 unsigned int, void *);
2027
2028#define KGSL_IOCTL_FUNC(_cmd, _func, _lock) \
2029 [_IOC_NR(_cmd)] = { .cmd = _cmd, .func = _func, .lock = _lock }
2030
2031static const struct {
2032 unsigned int cmd;
2033 kgsl_ioctl_func_t func;
2034 int lock;
2035} kgsl_ioctl_funcs[] = {
2036 KGSL_IOCTL_FUNC(IOCTL_KGSL_DEVICE_GETPROPERTY,
2037 kgsl_ioctl_device_getproperty, 1),
2038 KGSL_IOCTL_FUNC(IOCTL_KGSL_DEVICE_WAITTIMESTAMP,
2039 kgsl_ioctl_device_waittimestamp, 1),
Carter Cooper7e7f02e2012-02-15 09:36:31 -07002040 KGSL_IOCTL_FUNC(IOCTL_KGSL_DEVICE_WAITTIMESTAMP_CTXTID,
2041 kgsl_ioctl_device_waittimestamp_ctxtid, 1),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002042 KGSL_IOCTL_FUNC(IOCTL_KGSL_RINGBUFFER_ISSUEIBCMDS,
2043 kgsl_ioctl_rb_issueibcmds, 1),
2044 KGSL_IOCTL_FUNC(IOCTL_KGSL_CMDSTREAM_READTIMESTAMP,
2045 kgsl_ioctl_cmdstream_readtimestamp, 1),
Carter Cooper7e7f02e2012-02-15 09:36:31 -07002046 KGSL_IOCTL_FUNC(IOCTL_KGSL_CMDSTREAM_READTIMESTAMP_CTXTID,
2047 kgsl_ioctl_cmdstream_readtimestamp_ctxtid, 1),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002048 KGSL_IOCTL_FUNC(IOCTL_KGSL_CMDSTREAM_FREEMEMONTIMESTAMP,
2049 kgsl_ioctl_cmdstream_freememontimestamp, 1),
Carter Cooper7e7f02e2012-02-15 09:36:31 -07002050 KGSL_IOCTL_FUNC(IOCTL_KGSL_CMDSTREAM_FREEMEMONTIMESTAMP_CTXTID,
2051 kgsl_ioctl_cmdstream_freememontimestamp_ctxtid, 1),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002052 KGSL_IOCTL_FUNC(IOCTL_KGSL_DRAWCTXT_CREATE,
2053 kgsl_ioctl_drawctxt_create, 1),
2054 KGSL_IOCTL_FUNC(IOCTL_KGSL_DRAWCTXT_DESTROY,
2055 kgsl_ioctl_drawctxt_destroy, 1),
2056 KGSL_IOCTL_FUNC(IOCTL_KGSL_MAP_USER_MEM,
2057 kgsl_ioctl_map_user_mem, 0),
2058 KGSL_IOCTL_FUNC(IOCTL_KGSL_SHAREDMEM_FROM_PMEM,
2059 kgsl_ioctl_map_user_mem, 0),
2060 KGSL_IOCTL_FUNC(IOCTL_KGSL_SHAREDMEM_FREE,
2061 kgsl_ioctl_sharedmem_free, 0),
2062 KGSL_IOCTL_FUNC(IOCTL_KGSL_SHAREDMEM_FROM_VMALLOC,
2063 kgsl_ioctl_sharedmem_from_vmalloc, 0),
2064 KGSL_IOCTL_FUNC(IOCTL_KGSL_SHAREDMEM_FLUSH_CACHE,
2065 kgsl_ioctl_sharedmem_flush_cache, 0),
2066 KGSL_IOCTL_FUNC(IOCTL_KGSL_GPUMEM_ALLOC,
2067 kgsl_ioctl_gpumem_alloc, 0),
Jeremy Gebbena7423e42011-04-18 15:11:21 -06002068 KGSL_IOCTL_FUNC(IOCTL_KGSL_CFF_SYNCMEM,
2069 kgsl_ioctl_cff_syncmem, 0),
Sushmita Susheelendra41f8fa32011-05-11 17:15:58 -06002070 KGSL_IOCTL_FUNC(IOCTL_KGSL_CFF_USER_EVENT,
2071 kgsl_ioctl_cff_user_event, 0),
Jordan Croused4bc9d22011-11-17 13:39:21 -07002072 KGSL_IOCTL_FUNC(IOCTL_KGSL_TIMESTAMP_EVENT,
Lucille Sylvester9329cf02011-12-02 14:30:41 -07002073 kgsl_ioctl_timestamp_event, 1),
Jordan Crouseed7dd7f2012-03-29 13:16:02 -06002074 KGSL_IOCTL_FUNC(IOCTL_KGSL_SETPROPERTY,
2075 kgsl_ioctl_device_setproperty, 1),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002076};
2077
2078static long kgsl_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
2079{
2080 struct kgsl_device_private *dev_priv = filep->private_data;
2081 unsigned int nr = _IOC_NR(cmd);
2082 kgsl_ioctl_func_t func;
2083 int lock, ret;
2084 char ustack[64];
2085 void *uptr = NULL;
2086
2087 BUG_ON(dev_priv == NULL);
2088
2089 /* Workaround for an previously incorrectly defined ioctl code.
2090 This helps ensure binary compatability */
2091
2092 if (cmd == IOCTL_KGSL_CMDSTREAM_FREEMEMONTIMESTAMP_OLD)
2093 cmd = IOCTL_KGSL_CMDSTREAM_FREEMEMONTIMESTAMP;
Jason Varbedian80ba33d2011-07-11 17:29:05 -07002094 else if (cmd == IOCTL_KGSL_CMDSTREAM_READTIMESTAMP_OLD)
2095 cmd = IOCTL_KGSL_CMDSTREAM_READTIMESTAMP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002096
2097 if (cmd & (IOC_IN | IOC_OUT)) {
2098 if (_IOC_SIZE(cmd) < sizeof(ustack))
2099 uptr = ustack;
2100 else {
2101 uptr = kzalloc(_IOC_SIZE(cmd), GFP_KERNEL);
2102 if (uptr == NULL) {
2103 KGSL_MEM_ERR(dev_priv->device,
2104 "kzalloc(%d) failed\n", _IOC_SIZE(cmd));
2105 ret = -ENOMEM;
2106 goto done;
2107 }
2108 }
2109
2110 if (cmd & IOC_IN) {
2111 if (copy_from_user(uptr, (void __user *) arg,
2112 _IOC_SIZE(cmd))) {
2113 ret = -EFAULT;
2114 goto done;
2115 }
2116 } else
2117 memset(uptr, 0, _IOC_SIZE(cmd));
2118 }
2119
2120 if (nr < ARRAY_SIZE(kgsl_ioctl_funcs) &&
2121 kgsl_ioctl_funcs[nr].func != NULL) {
2122 func = kgsl_ioctl_funcs[nr].func;
2123 lock = kgsl_ioctl_funcs[nr].lock;
2124 } else {
2125 func = dev_priv->device->ftbl->ioctl;
2126 if (!func) {
2127 KGSL_DRV_INFO(dev_priv->device,
2128 "invalid ioctl code %08x\n", cmd);
Jeremy Gebbenc15b4612012-01-09 09:44:11 -07002129 ret = -ENOIOCTLCMD;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002130 goto done;
2131 }
2132 lock = 1;
2133 }
2134
2135 if (lock) {
2136 mutex_lock(&dev_priv->device->mutex);
2137 kgsl_check_suspended(dev_priv->device);
2138 }
2139
2140 ret = func(dev_priv, cmd, uptr);
2141
2142 if (lock) {
2143 kgsl_check_idle_locked(dev_priv->device);
2144 mutex_unlock(&dev_priv->device->mutex);
2145 }
2146
2147 if (ret == 0 && (cmd & IOC_OUT)) {
2148 if (copy_to_user((void __user *) arg, uptr, _IOC_SIZE(cmd)))
2149 ret = -EFAULT;
2150 }
2151
2152done:
2153 if (_IOC_SIZE(cmd) >= sizeof(ustack))
2154 kfree(uptr);
2155
2156 return ret;
2157}
2158
2159static int
2160kgsl_mmap_memstore(struct kgsl_device *device, struct vm_area_struct *vma)
2161{
2162 struct kgsl_memdesc *memdesc = &device->memstore;
2163 int result;
2164 unsigned int vma_size = vma->vm_end - vma->vm_start;
2165
2166 /* The memstore can only be mapped as read only */
2167
2168 if (vma->vm_flags & VM_WRITE)
2169 return -EPERM;
2170
2171 if (memdesc->size != vma_size) {
2172 KGSL_MEM_ERR(device, "memstore bad size: %d should be %d\n",
2173 vma_size, memdesc->size);
2174 return -EINVAL;
2175 }
2176
2177 vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
2178
2179 result = remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
2180 vma_size, vma->vm_page_prot);
2181 if (result != 0)
2182 KGSL_MEM_ERR(device, "remap_pfn_range failed: %d\n",
2183 result);
2184
2185 return result;
2186}
2187
Jordan Crouse4283e172011-09-26 14:45:47 -06002188/*
2189 * kgsl_gpumem_vm_open is called whenever a vma region is copied or split.
2190 * Increase the refcount to make sure that the accounting stays correct
2191 */
2192
2193static void kgsl_gpumem_vm_open(struct vm_area_struct *vma)
2194{
2195 struct kgsl_mem_entry *entry = vma->vm_private_data;
2196 kgsl_mem_entry_get(entry);
2197}
2198
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002199static int
2200kgsl_gpumem_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
2201{
2202 struct kgsl_mem_entry *entry = vma->vm_private_data;
2203
Jordan Croused17e9aa2011-10-12 16:57:48 -06002204 if (!entry->memdesc.ops || !entry->memdesc.ops->vmfault)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002205 return VM_FAULT_SIGBUS;
2206
2207 return entry->memdesc.ops->vmfault(&entry->memdesc, vma, vmf);
2208}
2209
2210static void
2211kgsl_gpumem_vm_close(struct vm_area_struct *vma)
2212{
2213 struct kgsl_mem_entry *entry = vma->vm_private_data;
2214 kgsl_mem_entry_put(entry);
2215}
2216
2217static struct vm_operations_struct kgsl_gpumem_vm_ops = {
Jordan Crouse4283e172011-09-26 14:45:47 -06002218 .open = kgsl_gpumem_vm_open,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002219 .fault = kgsl_gpumem_vm_fault,
2220 .close = kgsl_gpumem_vm_close,
2221};
2222
2223static int kgsl_mmap(struct file *file, struct vm_area_struct *vma)
2224{
2225 unsigned long vma_offset = vma->vm_pgoff << PAGE_SHIFT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002226 struct kgsl_device_private *dev_priv = file->private_data;
2227 struct kgsl_process_private *private = dev_priv->process_priv;
Jordan Crousec9559e42012-04-05 16:55:56 -06002228 struct kgsl_mem_entry *entry = NULL;
Jordan Crouse2db0af92011-08-08 16:05:09 -06002229 struct kgsl_device *device = dev_priv->device;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002230
2231 /* Handle leagacy behavior for memstore */
2232
2233 if (vma_offset == device->memstore.physaddr)
2234 return kgsl_mmap_memstore(device, vma);
2235
2236 /* Find a chunk of GPU memory */
2237
2238 spin_lock(&private->mem_lock);
Jordan Crousec9559e42012-04-05 16:55:56 -06002239 entry = kgsl_sharedmem_find(private, vma_offset);
2240
2241 if (entry)
2242 kgsl_mem_entry_get(entry);
2243
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002244 spin_unlock(&private->mem_lock);
2245
2246 if (entry == NULL)
2247 return -EINVAL;
2248
Jordan Croused17e9aa2011-10-12 16:57:48 -06002249 if (!entry->memdesc.ops ||
2250 !entry->memdesc.ops->vmflags ||
2251 !entry->memdesc.ops->vmfault)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002252 return -EINVAL;
2253
2254 vma->vm_flags |= entry->memdesc.ops->vmflags(&entry->memdesc);
2255
2256 vma->vm_private_data = entry;
2257 vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
2258 vma->vm_ops = &kgsl_gpumem_vm_ops;
2259 vma->vm_file = file;
2260
2261 return 0;
2262}
2263
2264static const struct file_operations kgsl_fops = {
2265 .owner = THIS_MODULE,
2266 .release = kgsl_release,
2267 .open = kgsl_open,
2268 .mmap = kgsl_mmap,
2269 .unlocked_ioctl = kgsl_ioctl,
2270};
2271
2272struct kgsl_driver kgsl_driver = {
2273 .process_mutex = __MUTEX_INITIALIZER(kgsl_driver.process_mutex),
2274 .ptlock = __SPIN_LOCK_UNLOCKED(kgsl_driver.ptlock),
2275 .devlock = __MUTEX_INITIALIZER(kgsl_driver.devlock),
2276};
2277EXPORT_SYMBOL(kgsl_driver);
2278
2279void kgsl_unregister_device(struct kgsl_device *device)
2280{
2281 int minor;
2282
2283 mutex_lock(&kgsl_driver.devlock);
2284 for (minor = 0; minor < KGSL_DEVICE_MAX; minor++) {
2285 if (device == kgsl_driver.devp[minor])
2286 break;
2287 }
2288
2289 mutex_unlock(&kgsl_driver.devlock);
2290
2291 if (minor == KGSL_DEVICE_MAX)
2292 return;
2293
Jordan Crouse156cfbc2012-01-24 09:32:04 -07002294 kgsl_device_snapshot_close(device);
2295
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002296 kgsl_cffdump_close(device->id);
2297 kgsl_pwrctrl_uninit_sysfs(device);
2298
Lucille Sylvester10297892012-02-27 13:54:47 -07002299 wake_lock_destroy(&device->idle_wakelock);
2300 pm_qos_remove_request(&device->pm_qos_req_dma);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002301
2302 idr_destroy(&device->context_idr);
2303
2304 if (device->memstore.hostptr)
2305 kgsl_sharedmem_free(&device->memstore);
2306
2307 kgsl_mmu_close(device);
2308
2309 if (device->work_queue) {
2310 destroy_workqueue(device->work_queue);
2311 device->work_queue = NULL;
2312 }
2313
2314 device_destroy(kgsl_driver.class,
2315 MKDEV(MAJOR(kgsl_driver.major), minor));
2316
2317 mutex_lock(&kgsl_driver.devlock);
2318 kgsl_driver.devp[minor] = NULL;
2319 mutex_unlock(&kgsl_driver.devlock);
2320}
2321EXPORT_SYMBOL(kgsl_unregister_device);
2322
2323int
2324kgsl_register_device(struct kgsl_device *device)
2325{
2326 int minor, ret;
2327 dev_t dev;
2328
2329 /* Find a minor for the device */
2330
2331 mutex_lock(&kgsl_driver.devlock);
2332 for (minor = 0; minor < KGSL_DEVICE_MAX; minor++) {
2333 if (kgsl_driver.devp[minor] == NULL) {
2334 kgsl_driver.devp[minor] = device;
2335 break;
2336 }
2337 }
2338
2339 mutex_unlock(&kgsl_driver.devlock);
2340
2341 if (minor == KGSL_DEVICE_MAX) {
2342 KGSL_CORE_ERR("minor devices exhausted\n");
2343 return -ENODEV;
2344 }
2345
2346 /* Create the device */
2347 dev = MKDEV(MAJOR(kgsl_driver.major), minor);
2348 device->dev = device_create(kgsl_driver.class,
2349 device->parentdev,
2350 dev, device,
2351 device->name);
2352
2353 if (IS_ERR(device->dev)) {
2354 ret = PTR_ERR(device->dev);
2355 KGSL_CORE_ERR("device_create(%s): %d\n", device->name, ret);
2356 goto err_devlist;
2357 }
2358
2359 dev_set_drvdata(device->parentdev, device);
2360
2361 /* Generic device initialization */
2362 init_waitqueue_head(&device->wait_queue);
2363
2364 kgsl_cffdump_open(device->id);
2365
2366 init_completion(&device->hwaccess_gate);
2367 init_completion(&device->suspend_gate);
2368
2369 ATOMIC_INIT_NOTIFIER_HEAD(&device->ts_notifier_list);
2370
2371 setup_timer(&device->idle_timer, kgsl_timer, (unsigned long) device);
2372 ret = kgsl_create_device_workqueue(device);
2373 if (ret)
2374 goto err_devlist;
2375
2376 INIT_WORK(&device->idle_check_ws, kgsl_idle_check);
Jordan Crouse1bf80aa2011-10-12 16:57:47 -06002377 INIT_WORK(&device->ts_expired_ws, kgsl_timestamp_expired);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002378
Jordan Croused4bc9d22011-11-17 13:39:21 -07002379 INIT_LIST_HEAD(&device->events);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002380
Carter Cooper7e7f02e2012-02-15 09:36:31 -07002381 device->last_expired_ctxt_id = KGSL_CONTEXT_INVALID;
2382
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002383 ret = kgsl_mmu_init(device);
2384 if (ret != 0)
2385 goto err_dest_work_q;
2386
Carter Cooper7e7f02e2012-02-15 09:36:31 -07002387 ret = kgsl_allocate_contiguous(&device->memstore, KGSL_MEMSTORE_SIZE);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002388 if (ret != 0)
2389 goto err_close_mmu;
2390
Lucille Sylvester10297892012-02-27 13:54:47 -07002391 wake_lock_init(&device->idle_wakelock, WAKE_LOCK_IDLE, device->name);
2392 pm_qos_add_request(&device->pm_qos_req_dma, PM_QOS_CPU_DMA_LATENCY,
2393 PM_QOS_DEFAULT_VALUE);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002394
2395 idr_init(&device->context_idr);
2396
Jordan Crouse156cfbc2012-01-24 09:32:04 -07002397 /* Initalize the snapshot engine */
2398 kgsl_device_snapshot_init(device);
2399
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002400 /* sysfs and debugfs initalization - failure here is non fatal */
2401
2402 /* Initialize logging */
2403 kgsl_device_debugfs_init(device);
2404
2405 /* Initialize common sysfs entries */
2406 kgsl_pwrctrl_init_sysfs(device);
2407
2408 return 0;
2409
2410err_close_mmu:
2411 kgsl_mmu_close(device);
2412err_dest_work_q:
2413 destroy_workqueue(device->work_queue);
2414 device->work_queue = NULL;
2415err_devlist:
2416 mutex_lock(&kgsl_driver.devlock);
2417 kgsl_driver.devp[minor] = NULL;
2418 mutex_unlock(&kgsl_driver.devlock);
2419
2420 return ret;
2421}
2422EXPORT_SYMBOL(kgsl_register_device);
2423
2424int kgsl_device_platform_probe(struct kgsl_device *device,
2425 irqreturn_t (*dev_isr) (int, void*))
2426{
Michael Street8bacdd02012-01-05 14:55:01 -08002427 int result;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002428 int status = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002429 struct resource *res;
2430 struct platform_device *pdev =
2431 container_of(device->parentdev, struct platform_device, dev);
2432
2433 pm_runtime_enable(device->parentdev);
2434
2435 status = kgsl_pwrctrl_init(device);
2436 if (status)
2437 goto error;
2438
Harsh Vardhan Dwivedif48af7f2012-04-13 12:50:44 -06002439 kgsl_ion_client = msm_ion_client_create(UINT_MAX, KGSL_NAME);
2440
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002441 res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
2442 device->iomemname);
2443 if (res == NULL) {
2444 KGSL_DRV_ERR(device, "platform_get_resource_byname failed\n");
2445 status = -EINVAL;
2446 goto error_pwrctrl_close;
2447 }
2448 if (res->start == 0 || resource_size(res) == 0) {
Jordan Crouse7501d452012-04-19 08:58:44 -06002449 KGSL_DRV_ERR(device, "dev %d invalid register region\n",
2450 device->id);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002451 status = -EINVAL;
2452 goto error_pwrctrl_close;
2453 }
2454
Jordan Crouse7501d452012-04-19 08:58:44 -06002455 device->reg_phys = res->start;
2456 device->reg_len = resource_size(res);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002457
Jordan Crouse7501d452012-04-19 08:58:44 -06002458 if (!request_mem_region(device->reg_phys, device->reg_len,
2459 device->name)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002460 KGSL_DRV_ERR(device, "request_mem_region failed\n");
2461 status = -ENODEV;
2462 goto error_pwrctrl_close;
2463 }
2464
Jordan Crouse7501d452012-04-19 08:58:44 -06002465 device->reg_virt = ioremap(device->reg_phys, device->reg_len);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002466
Jordan Crouse7501d452012-04-19 08:58:44 -06002467 if (device->reg_virt == NULL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002468 KGSL_DRV_ERR(device, "ioremap failed\n");
2469 status = -ENODEV;
2470 goto error_release_mem;
2471 }
2472
2473 status = request_irq(device->pwrctrl.interrupt_num, dev_isr,
2474 IRQF_TRIGGER_HIGH, device->name, device);
2475 if (status) {
2476 KGSL_DRV_ERR(device, "request_irq(%d) failed: %d\n",
2477 device->pwrctrl.interrupt_num, status);
2478 goto error_iounmap;
2479 }
2480 device->pwrctrl.have_irq = 1;
2481 disable_irq(device->pwrctrl.interrupt_num);
2482
2483 KGSL_DRV_INFO(device,
Jordan Crouse7501d452012-04-19 08:58:44 -06002484 "dev_id %d regs phys 0x%08lx size 0x%08x virt %p\n",
2485 device->id, device->reg_phys, device->reg_len,
2486 device->reg_virt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002487
Michael Street8bacdd02012-01-05 14:55:01 -08002488 result = kgsl_drm_init(pdev);
2489 if (result)
2490 goto error_iounmap;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002491
2492 status = kgsl_register_device(device);
2493 if (!status)
2494 return status;
2495
2496 free_irq(device->pwrctrl.interrupt_num, NULL);
2497 device->pwrctrl.have_irq = 0;
2498error_iounmap:
Jordan Crouse7501d452012-04-19 08:58:44 -06002499 iounmap(device->reg_virt);
2500 device->reg_virt = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002501error_release_mem:
Jordan Crouse7501d452012-04-19 08:58:44 -06002502 release_mem_region(device->reg_phys, device->reg_len);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002503error_pwrctrl_close:
2504 kgsl_pwrctrl_close(device);
2505error:
2506 return status;
2507}
2508EXPORT_SYMBOL(kgsl_device_platform_probe);
2509
2510void kgsl_device_platform_remove(struct kgsl_device *device)
2511{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002512 kgsl_unregister_device(device);
2513
Jordan Crouse7501d452012-04-19 08:58:44 -06002514 if (device->reg_virt != NULL) {
2515 iounmap(device->reg_virt);
2516 device->reg_virt = NULL;
2517 release_mem_region(device->reg_phys, device->reg_len);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002518 }
2519 kgsl_pwrctrl_close(device);
2520
2521 pm_runtime_disable(device->parentdev);
2522}
2523EXPORT_SYMBOL(kgsl_device_platform_remove);
2524
2525static int __devinit
2526kgsl_ptdata_init(void)
2527{
Jordan Crouse6d76c4d2012-03-26 09:50:43 -06002528 kgsl_driver.ptpool = kgsl_mmu_ptpool_init(kgsl_pagetable_count);
2529
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06002530 if (!kgsl_driver.ptpool)
2531 return -ENOMEM;
2532 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002533}
2534
2535static void kgsl_core_exit(void)
2536{
2537 unregister_chrdev_region(kgsl_driver.major, KGSL_DEVICE_MAX);
2538
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06002539 kgsl_mmu_ptpool_destroy(&kgsl_driver.ptpool);
2540 kgsl_driver.ptpool = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002541
2542 device_unregister(&kgsl_driver.virtdev);
2543
2544 if (kgsl_driver.class) {
2545 class_destroy(kgsl_driver.class);
2546 kgsl_driver.class = NULL;
2547 }
2548
2549 kgsl_drm_exit();
2550 kgsl_cffdump_destroy();
Jordan Croused8f1c6b2011-10-04 09:31:29 -06002551 kgsl_core_debugfs_close();
2552 kgsl_sharedmem_uninit_sysfs();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002553}
2554
2555static int __init kgsl_core_init(void)
2556{
2557 int result = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002558 /* alloc major and minor device numbers */
2559 result = alloc_chrdev_region(&kgsl_driver.major, 0, KGSL_DEVICE_MAX,
2560 KGSL_NAME);
2561 if (result < 0) {
2562 KGSL_CORE_ERR("alloc_chrdev_region failed err = %d\n", result);
2563 goto err;
2564 }
2565
2566 cdev_init(&kgsl_driver.cdev, &kgsl_fops);
2567 kgsl_driver.cdev.owner = THIS_MODULE;
2568 kgsl_driver.cdev.ops = &kgsl_fops;
2569 result = cdev_add(&kgsl_driver.cdev, MKDEV(MAJOR(kgsl_driver.major), 0),
2570 KGSL_DEVICE_MAX);
2571
2572 if (result) {
2573 KGSL_CORE_ERR("kgsl: cdev_add() failed, dev_num= %d,"
2574 " result= %d\n", kgsl_driver.major, result);
2575 goto err;
2576 }
2577
2578 kgsl_driver.class = class_create(THIS_MODULE, KGSL_NAME);
2579
2580 if (IS_ERR(kgsl_driver.class)) {
2581 result = PTR_ERR(kgsl_driver.class);
2582 KGSL_CORE_ERR("failed to create class %s", KGSL_NAME);
2583 goto err;
2584 }
2585
2586 /* Make a virtual device for managing core related things
2587 in sysfs */
2588 kgsl_driver.virtdev.class = kgsl_driver.class;
2589 dev_set_name(&kgsl_driver.virtdev, "kgsl");
2590 result = device_register(&kgsl_driver.virtdev);
2591 if (result) {
2592 KGSL_CORE_ERR("driver_register failed\n");
2593 goto err;
2594 }
2595
2596 /* Make kobjects in the virtual device for storing statistics */
2597
2598 kgsl_driver.ptkobj =
2599 kobject_create_and_add("pagetables",
2600 &kgsl_driver.virtdev.kobj);
2601
2602 kgsl_driver.prockobj =
2603 kobject_create_and_add("proc",
2604 &kgsl_driver.virtdev.kobj);
2605
2606 kgsl_core_debugfs_init();
2607
2608 kgsl_sharedmem_init_sysfs();
2609 kgsl_cffdump_init();
2610
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002611 INIT_LIST_HEAD(&kgsl_driver.process_list);
2612
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06002613 INIT_LIST_HEAD(&kgsl_driver.pagetable_list);
2614
2615 kgsl_mmu_set_mmutype(ksgl_mmu_type);
2616
2617 if (KGSL_MMU_TYPE_GPU == kgsl_mmu_get_mmutype()) {
2618 result = kgsl_ptdata_init();
2619 if (result)
2620 goto err;
2621 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002622
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002623 return 0;
2624
2625err:
2626 kgsl_core_exit();
2627 return result;
2628}
2629
2630module_init(kgsl_core_init);
2631module_exit(kgsl_core_exit);
2632
2633MODULE_AUTHOR("Qualcomm Innovation Center, Inc.");
2634MODULE_DESCRIPTION("MSM GPU driver");
2635MODULE_LICENSE("GPL");