blob: 53eff77ff1c0a71f7014517385ad92db5569781e [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 */
Steve Mucklef132c6c2012-06-06 18:30:57 -070013#include <linux/module.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070014#include <linux/fb.h>
15#include <linux/file.h>
16#include <linux/fs.h>
17#include <linux/debugfs.h>
18#include <linux/uaccess.h>
19#include <linux/interrupt.h>
20#include <linux/workqueue.h>
21#include <linux/android_pmem.h>
22#include <linux/vmalloc.h>
23#include <linux/pm_runtime.h>
Jordan Croused4bc9d22011-11-17 13:39:21 -070024#include <linux/genlock.h>
Jordan Crousec9559e42012-04-05 16:55:56 -060025#include <linux/rbtree.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070026#include <linux/ashmem.h>
27#include <linux/major.h>
Jordan Crouse8eab35a2011-10-12 16:57:48 -060028#include <linux/ion.h>
Jeremy Gebben4204d0f2012-03-01 16:06:21 -070029#include <linux/io.h>
30#include <mach/socinfo.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070031
32#include "kgsl.h"
33#include "kgsl_debugfs.h"
34#include "kgsl_cffdump.h"
35#include "kgsl_log.h"
36#include "kgsl_sharedmem.h"
37#include "kgsl_device.h"
Norman Geed7402ff2011-10-28 08:51:11 -060038#include "kgsl_trace.h"
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070039
40#undef MODULE_PARAM_PREFIX
41#define MODULE_PARAM_PREFIX "kgsl."
42
43static int kgsl_pagetable_count = KGSL_PAGETABLE_COUNT;
Shubhraprakash Das767fdda2011-08-15 15:49:45 -060044static char *ksgl_mmu_type;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070045module_param_named(ptcount, kgsl_pagetable_count, int, 0);
46MODULE_PARM_DESC(kgsl_pagetable_count,
47"Minimum number of pagetables for KGSL to allocate at initialization time");
Shubhraprakash Das767fdda2011-08-15 15:49:45 -060048module_param_named(mmutype, ksgl_mmu_type, charp, 0);
49MODULE_PARM_DESC(ksgl_mmu_type,
50"Type of MMU to be used for graphics. Valid values are 'iommu' or 'gpummu' or 'nommu'");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070051
Jordan Crouse8eab35a2011-10-12 16:57:48 -060052static struct ion_client *kgsl_ion_client;
53
Jordan Croused4bc9d22011-11-17 13:39:21 -070054/**
55 * kgsl_add_event - Add a new timstamp event for the KGSL device
56 * @device - KGSL device for the new event
57 * @ts - the timestamp to trigger the event on
58 * @cb - callback function to call when the timestamp expires
59 * @priv - private data for the specific event type
Jeremy Gebbenfd87f9a2012-02-10 07:06:09 -070060 * @owner - driver instance that owns this event
Jordan Croused4bc9d22011-11-17 13:39:21 -070061 *
62 * @returns - 0 on success or error code on failure
63 */
64
Shubhraprakash Dascb068072012-06-07 17:52:41 -060065int kgsl_add_event(struct kgsl_device *device, u32 id, u32 ts,
Carter Cooper7e7f02e2012-02-15 09:36:31 -070066 void (*cb)(struct kgsl_device *, void *, u32, u32), void *priv,
Shubhraprakash Dascb068072012-06-07 17:52:41 -060067 void *owner)
Jordan Croused4bc9d22011-11-17 13:39:21 -070068{
69 struct kgsl_event *event;
70 struct list_head *n;
Carter Cooper7e7f02e2012-02-15 09:36:31 -070071 unsigned int cur_ts;
72 struct kgsl_context *context = NULL;
Jordan Croused4bc9d22011-11-17 13:39:21 -070073
74 if (cb == NULL)
75 return -EINVAL;
76
Carter Cooper7e7f02e2012-02-15 09:36:31 -070077 if (id != KGSL_MEMSTORE_GLOBAL) {
78 context = idr_find(&device->context_idr, id);
79 if (context == NULL)
80 return -EINVAL;
81 }
Jeremy Gebben731dac52012-05-10 11:13:42 -060082 cur_ts = kgsl_readtimestamp(device, context, KGSL_TIMESTAMP_RETIRED);
Carter Cooper7e7f02e2012-02-15 09:36:31 -070083
Jordan Croused4bc9d22011-11-17 13:39:21 -070084 /* Check to see if the requested timestamp has already fired */
85
Carter Cooper7e7f02e2012-02-15 09:36:31 -070086 if (timestamp_cmp(cur_ts, ts) >= 0) {
87 cb(device, priv, id, cur_ts);
Jordan Croused4bc9d22011-11-17 13:39:21 -070088 return 0;
89 }
90
91 event = kzalloc(sizeof(*event), GFP_KERNEL);
92 if (event == NULL)
93 return -ENOMEM;
94
Carter Cooper7e7f02e2012-02-15 09:36:31 -070095 event->context = context;
Jordan Croused4bc9d22011-11-17 13:39:21 -070096 event->timestamp = ts;
97 event->priv = priv;
98 event->func = cb;
Jeremy Gebbenfd87f9a2012-02-10 07:06:09 -070099 event->owner = owner;
Jordan Croused4bc9d22011-11-17 13:39:21 -0700100
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700101 /*
102 * Add the event in order to the list. Order is by context id
103 * first and then by timestamp for that context.
104 */
Jordan Croused4bc9d22011-11-17 13:39:21 -0700105
106 for (n = device->events.next ; n != &device->events; n = n->next) {
107 struct kgsl_event *e =
108 list_entry(n, struct kgsl_event, list);
109
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700110 if (e->context != context)
111 continue;
112
Jordan Croused4bc9d22011-11-17 13:39:21 -0700113 if (timestamp_cmp(e->timestamp, ts) > 0) {
114 list_add(&event->list, n->prev);
115 break;
116 }
117 }
118
119 if (n == &device->events)
120 list_add_tail(&event->list, &device->events);
121
Jeremy Gebben63904832012-02-07 16:10:55 -0700122 queue_work(device->work_queue, &device->ts_expired_ws);
Jordan Croused4bc9d22011-11-17 13:39:21 -0700123 return 0;
124}
Shubhraprakash Dascb068072012-06-07 17:52:41 -0600125EXPORT_SYMBOL(kgsl_add_event);
Jordan Croused4bc9d22011-11-17 13:39:21 -0700126
Jeremy Gebbenfd87f9a2012-02-10 07:06:09 -0700127/**
Lynus Vazf519d2c2012-04-25 15:46:08 +0530128 * kgsl_cancel_events_ctxt - Cancel all events for a context
129 * @device - KGSL device for the events to cancel
130 * @ctxt - context whose events we want to cancel
131 *
132 */
133static void kgsl_cancel_events_ctxt(struct kgsl_device *device,
134 struct kgsl_context *context)
135{
136 struct kgsl_event *event, *event_tmp;
137 unsigned int id, cur;
138
Jeremy Gebben731dac52012-05-10 11:13:42 -0600139 cur = kgsl_readtimestamp(device, context, KGSL_TIMESTAMP_RETIRED);
Lynus Vazf519d2c2012-04-25 15:46:08 +0530140 id = context->id;
141
142 list_for_each_entry_safe(event, event_tmp, &device->events, list) {
143 if (event->context != context)
144 continue;
145
146 /*
147 * "cancel" the events by calling their callback.
148 * Currently, events are used for lock and memory
149 * management, so if the process is dying the right
150 * thing to do is release or free.
151 */
152 if (event->func)
153 event->func(device, event->priv, id, cur);
154
155 list_del(&event->list);
156 kfree(event);
157 }
158}
159
160/**
Jeremy Gebbenfd87f9a2012-02-10 07:06:09 -0700161 * kgsl_cancel_events - Cancel all events for a process
162 * @device - KGSL device for the events to cancel
163 * @owner - driver instance that owns the events to cancel
164 *
165 */
Shubhraprakash Dascb068072012-06-07 17:52:41 -0600166void kgsl_cancel_events(struct kgsl_device *device,
167 void *owner)
Jeremy Gebbenfd87f9a2012-02-10 07:06:09 -0700168{
169 struct kgsl_event *event, *event_tmp;
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700170 unsigned int id, cur;
Jeremy Gebbenfd87f9a2012-02-10 07:06:09 -0700171
172 list_for_each_entry_safe(event, event_tmp, &device->events, list) {
173 if (event->owner != owner)
174 continue;
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700175
Jeremy Gebben731dac52012-05-10 11:13:42 -0600176 cur = kgsl_readtimestamp(device, event->context,
177 KGSL_TIMESTAMP_RETIRED);
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700178
179 id = event->context ? event->context->id : KGSL_MEMSTORE_GLOBAL;
Jeremy Gebbenfd87f9a2012-02-10 07:06:09 -0700180 /*
181 * "cancel" the events by calling their callback.
182 * Currently, events are used for lock and memory
183 * management, so if the process is dying the right
184 * thing to do is release or free.
185 */
186 if (event->func)
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700187 event->func(device, event->priv, id, cur);
Jeremy Gebbenfd87f9a2012-02-10 07:06:09 -0700188
189 list_del(&event->list);
190 kfree(event);
191 }
192}
Shubhraprakash Dascb068072012-06-07 17:52:41 -0600193EXPORT_SYMBOL(kgsl_cancel_events);
Jeremy Gebbenfd87f9a2012-02-10 07:06:09 -0700194
Jordan Crouse0fdf3a02012-03-16 14:53:41 -0600195/* kgsl_get_mem_entry - get the mem_entry structure for the specified object
196 * @ptbase - the pagetable base of the object
197 * @gpuaddr - the GPU address of the object
198 * @size - Size of the region to search
199 */
200
201struct kgsl_mem_entry *kgsl_get_mem_entry(unsigned int ptbase,
202 unsigned int gpuaddr, unsigned int size)
203{
204 struct kgsl_process_private *priv;
205 struct kgsl_mem_entry *entry;
206
207 mutex_lock(&kgsl_driver.process_mutex);
208
209 list_for_each_entry(priv, &kgsl_driver.process_list, list) {
210 if (!kgsl_mmu_pt_equal(priv->pagetable, ptbase))
211 continue;
212 spin_lock(&priv->mem_lock);
213 entry = kgsl_sharedmem_find_region(priv, gpuaddr, size);
214
215 if (entry) {
216 spin_unlock(&priv->mem_lock);
217 mutex_unlock(&kgsl_driver.process_mutex);
218 return entry;
219 }
220 spin_unlock(&priv->mem_lock);
221 }
222 mutex_unlock(&kgsl_driver.process_mutex);
223
224 return NULL;
225}
226EXPORT_SYMBOL(kgsl_get_mem_entry);
227
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700228static inline struct kgsl_mem_entry *
229kgsl_mem_entry_create(void)
230{
231 struct kgsl_mem_entry *entry = kzalloc(sizeof(*entry), GFP_KERNEL);
232
233 if (!entry)
234 KGSL_CORE_ERR("kzalloc(%d) failed\n", sizeof(*entry));
235 else
236 kref_init(&entry->refcount);
237
238 return entry;
239}
240
241void
242kgsl_mem_entry_destroy(struct kref *kref)
243{
244 struct kgsl_mem_entry *entry = container_of(kref,
245 struct kgsl_mem_entry,
246 refcount);
Jordan Crouse1b897cf2011-10-12 16:57:48 -0600247
Jordan Crouse1b897cf2011-10-12 16:57:48 -0600248 if (entry->memtype != KGSL_MEM_ENTRY_KERNEL)
249 kgsl_driver.stats.mapped -= entry->memdesc.size;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700250
Jordan Crouse8eab35a2011-10-12 16:57:48 -0600251 /*
Laura Abbottb14ed962012-01-30 14:18:08 -0800252 * Ion takes care of freeing the sglist for us so
253 * clear the sg before freeing the sharedmem so kgsl_sharedmem_free
Jordan Crouse8eab35a2011-10-12 16:57:48 -0600254 * doesn't try to free it again
255 */
256
257 if (entry->memtype == KGSL_MEM_ENTRY_ION) {
Jordan Crouse8eab35a2011-10-12 16:57:48 -0600258 entry->memdesc.sg = NULL;
259 }
260
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700261 kgsl_sharedmem_free(&entry->memdesc);
262
Jordan Crouse1b897cf2011-10-12 16:57:48 -0600263 switch (entry->memtype) {
264 case KGSL_MEM_ENTRY_PMEM:
265 case KGSL_MEM_ENTRY_ASHMEM:
266 if (entry->priv_data)
267 fput(entry->priv_data);
268 break;
Jordan Crouse8eab35a2011-10-12 16:57:48 -0600269 case KGSL_MEM_ENTRY_ION:
270 ion_free(kgsl_ion_client, entry->priv_data);
271 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700272 }
273
274 kfree(entry);
275}
276EXPORT_SYMBOL(kgsl_mem_entry_destroy);
277
278static
279void kgsl_mem_entry_attach_process(struct kgsl_mem_entry *entry,
280 struct kgsl_process_private *process)
281{
Jordan Crousec9559e42012-04-05 16:55:56 -0600282 struct rb_node **node;
283 struct rb_node *parent = NULL;
284
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700285 spin_lock(&process->mem_lock);
Jordan Crousec9559e42012-04-05 16:55:56 -0600286
287 node = &process->mem_rb.rb_node;
288
289 while (*node) {
290 struct kgsl_mem_entry *cur;
291
292 parent = *node;
293 cur = rb_entry(parent, struct kgsl_mem_entry, node);
294
295 if (entry->memdesc.gpuaddr < cur->memdesc.gpuaddr)
296 node = &parent->rb_left;
297 else
298 node = &parent->rb_right;
299 }
300
301 rb_link_node(&entry->node, parent, node);
302 rb_insert_color(&entry->node, &process->mem_rb);
303
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700304 spin_unlock(&process->mem_lock);
305
306 entry->priv = process;
307}
308
Jordan Crouse00714012012-03-16 14:53:40 -0600309/* Detach a memory entry from a process and unmap it from the MMU */
310
311static void kgsl_mem_entry_detach_process(struct kgsl_mem_entry *entry)
312{
313 if (entry == NULL)
314 return;
315
316 entry->priv->stats[entry->memtype].cur -= entry->memdesc.size;
317 entry->priv = NULL;
318
319 kgsl_mmu_unmap(entry->memdesc.pagetable, &entry->memdesc);
320
321 kgsl_mem_entry_put(entry);
322}
323
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700324/* Allocate a new context id */
325
326static struct kgsl_context *
327kgsl_create_context(struct kgsl_device_private *dev_priv)
328{
329 struct kgsl_context *context;
330 int ret, id;
331
332 context = kzalloc(sizeof(*context), GFP_KERNEL);
333
334 if (context == NULL)
335 return NULL;
336
337 while (1) {
338 if (idr_pre_get(&dev_priv->device->context_idr,
339 GFP_KERNEL) == 0) {
340 kfree(context);
341 return NULL;
342 }
343
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700344 ret = idr_get_new_above(&dev_priv->device->context_idr,
345 context, 1, &id);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700346
347 if (ret != -EAGAIN)
348 break;
349 }
350
351 if (ret) {
352 kfree(context);
353 return NULL;
354 }
355
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700356 /* MAX - 1, there is one memdesc in memstore for device info */
357 if (id >= KGSL_MEMSTORE_MAX) {
358 KGSL_DRV_ERR(dev_priv->device, "cannot have more than %d "
359 "ctxts due to memstore limitation\n",
360 KGSL_MEMSTORE_MAX);
361 idr_remove(&dev_priv->device->context_idr, id);
362 kfree(context);
363 return NULL;
364 }
365
Jeremy Gebben9ad86922012-05-08 15:33:23 -0600366 kref_init(&context->refcount);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700367 context->id = id;
368 context->dev_priv = dev_priv;
369
370 return context;
371}
372
Jeremy Gebben9ad86922012-05-08 15:33:23 -0600373/**
374 * kgsl_context_detach - Release the "master" context reference
375 * @context - The context that will be detached
376 *
377 * This is called when a context becomes unusable, because userspace
378 * has requested for it to be destroyed. The context itself may
379 * exist a bit longer until its reference count goes to zero.
380 * Other code referencing the context can detect that it has been
381 * detached because the context id will be set to KGSL_CONTEXT_INVALID.
382 */
383void
384kgsl_context_detach(struct kgsl_context *context)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700385{
386 int id;
Jeremy Gebben9ad86922012-05-08 15:33:23 -0600387 struct kgsl_device *device;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700388 if (context == NULL)
389 return;
Jeremy Gebben9ad86922012-05-08 15:33:23 -0600390 device = context->dev_priv->device;
Jeremy Gebben4a3756c2012-05-08 16:51:43 -0600391 trace_kgsl_context_detach(device, context);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700392 id = context->id;
Jeremy Gebben1384a6a2012-05-17 14:34:17 -0600393
Jeremy Gebben9ad86922012-05-08 15:33:23 -0600394 if (device->ftbl->drawctxt_destroy)
395 device->ftbl->drawctxt_destroy(device, context);
396 /*device specific drawctxt_destroy MUST clean up devctxt */
397 BUG_ON(context->devctxt);
Jeremy Gebben1384a6a2012-05-17 14:34:17 -0600398 /*
399 * Cancel events after the device-specific context is
400 * destroyed, to avoid possibly freeing memory while
401 * it is still in use by the GPU.
402 */
403 kgsl_cancel_events_ctxt(device, context);
Jeremy Gebben9ad86922012-05-08 15:33:23 -0600404 idr_remove(&device->context_idr, id);
405 context->id = KGSL_CONTEXT_INVALID;
406 kgsl_context_put(context);
407}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700408
Jeremy Gebben9ad86922012-05-08 15:33:23 -0600409void
410kgsl_context_destroy(struct kref *kref)
411{
412 struct kgsl_context *context = container_of(kref, struct kgsl_context,
413 refcount);
414 kfree(context);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700415}
416
Jeremy Gebben84d75d02012-03-01 14:47:45 -0700417void kgsl_timestamp_expired(struct work_struct *work)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700418{
Jordan Crouse1bf80aa2011-10-12 16:57:47 -0600419 struct kgsl_device *device = container_of(work, struct kgsl_device,
420 ts_expired_ws);
Jordan Croused4bc9d22011-11-17 13:39:21 -0700421 struct kgsl_event *event, *event_tmp;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700422 uint32_t ts_processed;
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700423 unsigned int id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700424
Jordan Crouse1bf80aa2011-10-12 16:57:47 -0600425 mutex_lock(&device->mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700426
Jordan Croused4bc9d22011-11-17 13:39:21 -0700427 /* Process expired events */
428 list_for_each_entry_safe(event, event_tmp, &device->events, list) {
Jeremy Gebben731dac52012-05-10 11:13:42 -0600429 ts_processed = kgsl_readtimestamp(device, event->context,
430 KGSL_TIMESTAMP_RETIRED);
Jordan Croused4bc9d22011-11-17 13:39:21 -0700431 if (timestamp_cmp(ts_processed, event->timestamp) < 0)
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700432 continue;
433
434 id = event->context ? event->context->id : KGSL_MEMSTORE_GLOBAL;
Jordan Croused4bc9d22011-11-17 13:39:21 -0700435
436 if (event->func)
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700437 event->func(device, event->priv, id, ts_processed);
Jordan Croused4bc9d22011-11-17 13:39:21 -0700438
439 list_del(&event->list);
440 kfree(event);
441 }
442
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700443 mutex_unlock(&device->mutex);
444}
Jeremy Gebben84d75d02012-03-01 14:47:45 -0700445EXPORT_SYMBOL(kgsl_timestamp_expired);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700446
447static void kgsl_check_idle_locked(struct kgsl_device *device)
448{
449 if (device->pwrctrl.nap_allowed == true &&
450 device->state == KGSL_STATE_ACTIVE &&
451 device->requested_state == KGSL_STATE_NONE) {
Jeremy Gebben388c2972011-12-16 09:05:07 -0700452 kgsl_pwrctrl_request_state(device, KGSL_STATE_NAP);
Suman Tatiraju3de11cc2012-06-20 10:33:32 -0700453 kgsl_pwrscale_idle(device, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700454 if (kgsl_pwrctrl_sleep(device) != 0)
455 mod_timer(&device->idle_timer,
456 jiffies +
457 device->pwrctrl.interval_timeout);
458 }
459}
460
461static void kgsl_check_idle(struct kgsl_device *device)
462{
463 mutex_lock(&device->mutex);
464 kgsl_check_idle_locked(device);
465 mutex_unlock(&device->mutex);
466}
467
468struct kgsl_device *kgsl_get_device(int dev_idx)
469{
470 int i;
471 struct kgsl_device *ret = NULL;
472
473 mutex_lock(&kgsl_driver.devlock);
474
475 for (i = 0; i < KGSL_DEVICE_MAX; i++) {
476 if (kgsl_driver.devp[i] && kgsl_driver.devp[i]->id == dev_idx) {
477 ret = kgsl_driver.devp[i];
478 break;
479 }
480 }
481
482 mutex_unlock(&kgsl_driver.devlock);
483 return ret;
484}
485EXPORT_SYMBOL(kgsl_get_device);
486
487static struct kgsl_device *kgsl_get_minor(int minor)
488{
489 struct kgsl_device *ret = NULL;
490
491 if (minor < 0 || minor >= KGSL_DEVICE_MAX)
492 return NULL;
493
494 mutex_lock(&kgsl_driver.devlock);
495 ret = kgsl_driver.devp[minor];
496 mutex_unlock(&kgsl_driver.devlock);
497
498 return ret;
499}
500
501int kgsl_register_ts_notifier(struct kgsl_device *device,
502 struct notifier_block *nb)
503{
504 BUG_ON(device == NULL);
505 return atomic_notifier_chain_register(&device->ts_notifier_list,
506 nb);
507}
508EXPORT_SYMBOL(kgsl_register_ts_notifier);
509
510int kgsl_unregister_ts_notifier(struct kgsl_device *device,
511 struct notifier_block *nb)
512{
513 BUG_ON(device == NULL);
514 return atomic_notifier_chain_unregister(&device->ts_notifier_list,
515 nb);
516}
517EXPORT_SYMBOL(kgsl_unregister_ts_notifier);
518
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700519int kgsl_check_timestamp(struct kgsl_device *device,
520 struct kgsl_context *context, unsigned int timestamp)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700521{
522 unsigned int ts_processed;
523
Jeremy Gebben731dac52012-05-10 11:13:42 -0600524 ts_processed = kgsl_readtimestamp(device, context,
525 KGSL_TIMESTAMP_RETIRED);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700526
Jordan Crousee6239dd2011-11-17 13:39:21 -0700527 return (timestamp_cmp(ts_processed, timestamp) >= 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700528}
529EXPORT_SYMBOL(kgsl_check_timestamp);
530
531static int kgsl_suspend_device(struct kgsl_device *device, pm_message_t state)
532{
533 int status = -EINVAL;
534 unsigned int nap_allowed_saved;
535 struct kgsl_pwrscale_policy *policy_saved;
536
537 if (!device)
538 return -EINVAL;
539
540 KGSL_PWR_WARN(device, "suspend start\n");
541
542 mutex_lock(&device->mutex);
543 nap_allowed_saved = device->pwrctrl.nap_allowed;
544 device->pwrctrl.nap_allowed = false;
545 policy_saved = device->pwrscale.policy;
546 device->pwrscale.policy = NULL;
Jeremy Gebben388c2972011-12-16 09:05:07 -0700547 kgsl_pwrctrl_request_state(device, KGSL_STATE_SUSPEND);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700548 /* Make sure no user process is waiting for a timestamp *
549 * before supending */
550 if (device->active_cnt != 0) {
551 mutex_unlock(&device->mutex);
552 wait_for_completion(&device->suspend_gate);
553 mutex_lock(&device->mutex);
554 }
Suman Tatiraju4a32c652012-02-17 11:59:05 -0800555 /* Don't let the timer wake us during suspended sleep. */
556 del_timer_sync(&device->idle_timer);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700557 switch (device->state) {
558 case KGSL_STATE_INIT:
559 break;
560 case KGSL_STATE_ACTIVE:
561 /* Wait for the device to become idle */
562 device->ftbl->idle(device, KGSL_TIMEOUT_DEFAULT);
563 case KGSL_STATE_NAP:
564 case KGSL_STATE_SLEEP:
565 /* Get the completion ready to be waited upon. */
566 INIT_COMPLETION(device->hwaccess_gate);
567 device->ftbl->suspend_context(device);
568 device->ftbl->stop(device);
Suman Tatiraju48e72762012-05-03 11:12:03 -0700569 pm_qos_update_request(&device->pm_qos_req_dma,
570 PM_QOS_DEFAULT_VALUE);
Jeremy Gebben388c2972011-12-16 09:05:07 -0700571 kgsl_pwrctrl_set_state(device, KGSL_STATE_SUSPEND);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700572 break;
Suman Tatiraju24569022011-10-27 11:11:12 -0700573 case KGSL_STATE_SLUMBER:
574 INIT_COMPLETION(device->hwaccess_gate);
Jeremy Gebben388c2972011-12-16 09:05:07 -0700575 kgsl_pwrctrl_set_state(device, KGSL_STATE_SUSPEND);
Suman Tatiraju24569022011-10-27 11:11:12 -0700576 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700577 default:
578 KGSL_PWR_ERR(device, "suspend fail, device %d\n",
579 device->id);
580 goto end;
581 }
Jeremy Gebben388c2972011-12-16 09:05:07 -0700582 kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700583 device->pwrctrl.nap_allowed = nap_allowed_saved;
584 device->pwrscale.policy = policy_saved;
585 status = 0;
586
587end:
588 mutex_unlock(&device->mutex);
589 KGSL_PWR_WARN(device, "suspend end\n");
590 return status;
591}
592
593static int kgsl_resume_device(struct kgsl_device *device)
594{
595 int status = -EINVAL;
596
597 if (!device)
598 return -EINVAL;
599
600 KGSL_PWR_WARN(device, "resume start\n");
601 mutex_lock(&device->mutex);
602 if (device->state == KGSL_STATE_SUSPEND) {
Jeremy Gebben388c2972011-12-16 09:05:07 -0700603 kgsl_pwrctrl_set_state(device, KGSL_STATE_SLUMBER);
Suman Tatiraju24569022011-10-27 11:11:12 -0700604 status = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700605 complete_all(&device->hwaccess_gate);
606 }
Jeremy Gebben388c2972011-12-16 09:05:07 -0700607 kgsl_pwrctrl_request_state(device, KGSL_STATE_NONE);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700608
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700609 mutex_unlock(&device->mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700610 KGSL_PWR_WARN(device, "resume end\n");
611 return status;
612}
613
614static int kgsl_suspend(struct device *dev)
615{
616
617 pm_message_t arg = {0};
618 struct kgsl_device *device = dev_get_drvdata(dev);
619 return kgsl_suspend_device(device, arg);
620}
621
622static int kgsl_resume(struct device *dev)
623{
624 struct kgsl_device *device = dev_get_drvdata(dev);
625 return kgsl_resume_device(device);
626}
627
628static int kgsl_runtime_suspend(struct device *dev)
629{
630 return 0;
631}
632
633static int kgsl_runtime_resume(struct device *dev)
634{
635 return 0;
636}
637
638const struct dev_pm_ops kgsl_pm_ops = {
639 .suspend = kgsl_suspend,
640 .resume = kgsl_resume,
641 .runtime_suspend = kgsl_runtime_suspend,
642 .runtime_resume = kgsl_runtime_resume,
643};
644EXPORT_SYMBOL(kgsl_pm_ops);
645
646void kgsl_early_suspend_driver(struct early_suspend *h)
647{
648 struct kgsl_device *device = container_of(h,
649 struct kgsl_device, display_off);
Suman Tatiraju24569022011-10-27 11:11:12 -0700650 KGSL_PWR_WARN(device, "early suspend start\n");
Ranjhith Kalisamy8b636952011-09-03 14:48:31 +0530651 mutex_lock(&device->mutex);
Lucille Sylvester344e4622012-01-18 15:53:21 -0700652 kgsl_pwrctrl_request_state(device, KGSL_STATE_SLUMBER);
Suman Tatiraju24569022011-10-27 11:11:12 -0700653 kgsl_pwrctrl_sleep(device);
Ranjhith Kalisamy8b636952011-09-03 14:48:31 +0530654 mutex_unlock(&device->mutex);
Suman Tatiraju24569022011-10-27 11:11:12 -0700655 KGSL_PWR_WARN(device, "early suspend end\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700656}
657EXPORT_SYMBOL(kgsl_early_suspend_driver);
658
659int kgsl_suspend_driver(struct platform_device *pdev,
660 pm_message_t state)
661{
662 struct kgsl_device *device = dev_get_drvdata(&pdev->dev);
663 return kgsl_suspend_device(device, state);
664}
665EXPORT_SYMBOL(kgsl_suspend_driver);
666
667int kgsl_resume_driver(struct platform_device *pdev)
668{
669 struct kgsl_device *device = dev_get_drvdata(&pdev->dev);
670 return kgsl_resume_device(device);
671}
672EXPORT_SYMBOL(kgsl_resume_driver);
673
674void kgsl_late_resume_driver(struct early_suspend *h)
675{
676 struct kgsl_device *device = container_of(h,
677 struct kgsl_device, display_off);
Suman Tatiraju24569022011-10-27 11:11:12 -0700678 KGSL_PWR_WARN(device, "late resume start\n");
Ranjhith Kalisamy8b636952011-09-03 14:48:31 +0530679 mutex_lock(&device->mutex);
Suman Tatiraju24569022011-10-27 11:11:12 -0700680 device->pwrctrl.restore_slumber = 0;
Nilesh Shah94bdf2f2012-05-02 22:42:57 +0530681 if (device->pwrscale.policy == NULL)
682 kgsl_pwrctrl_pwrlevel_change(device, KGSL_PWRLEVEL_TURBO);
Suman Tatiraju3005cdd2012-03-19 14:38:11 -0700683 kgsl_pwrctrl_wake(device);
Ranjhith Kalisamy8b636952011-09-03 14:48:31 +0530684 mutex_unlock(&device->mutex);
Suman Tatiraju24569022011-10-27 11:11:12 -0700685 kgsl_check_idle(device);
686 KGSL_PWR_WARN(device, "late resume end\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700687}
688EXPORT_SYMBOL(kgsl_late_resume_driver);
689
690/* file operations */
691static struct kgsl_process_private *
692kgsl_get_process_private(struct kgsl_device_private *cur_dev_priv)
693{
694 struct kgsl_process_private *private;
695
696 mutex_lock(&kgsl_driver.process_mutex);
697 list_for_each_entry(private, &kgsl_driver.process_list, list) {
698 if (private->pid == task_tgid_nr(current)) {
699 private->refcnt++;
700 goto out;
701 }
702 }
703
704 /* no existing process private found for this dev_priv, create one */
705 private = kzalloc(sizeof(struct kgsl_process_private), GFP_KERNEL);
706 if (private == NULL) {
707 KGSL_DRV_ERR(cur_dev_priv->device, "kzalloc(%d) failed\n",
708 sizeof(struct kgsl_process_private));
709 goto out;
710 }
711
712 spin_lock_init(&private->mem_lock);
713 private->refcnt = 1;
714 private->pid = task_tgid_nr(current);
Jordan Crousec9559e42012-04-05 16:55:56 -0600715 private->mem_rb = RB_ROOT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700716
Shubhraprakash Das767fdda2011-08-15 15:49:45 -0600717 if (kgsl_mmu_enabled())
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700718 {
719 unsigned long pt_name;
720
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700721 pt_name = task_tgid_nr(current);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700722 private->pagetable = kgsl_mmu_getpagetable(pt_name);
723 if (private->pagetable == NULL) {
724 kfree(private);
725 private = NULL;
726 goto out;
727 }
728 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700729
730 list_add(&private->list, &kgsl_driver.process_list);
731
732 kgsl_process_init_sysfs(private);
733
734out:
735 mutex_unlock(&kgsl_driver.process_mutex);
736 return private;
737}
738
739static void
740kgsl_put_process_private(struct kgsl_device *device,
741 struct kgsl_process_private *private)
742{
743 struct kgsl_mem_entry *entry = NULL;
Jordan Crousec9559e42012-04-05 16:55:56 -0600744 struct rb_node *node;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700745
746 if (!private)
747 return;
748
749 mutex_lock(&kgsl_driver.process_mutex);
750
751 if (--private->refcnt)
752 goto unlock;
753
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700754 kgsl_process_uninit_sysfs(private);
755
756 list_del(&private->list);
757
Jordan Crousec9559e42012-04-05 16:55:56 -0600758 for (node = rb_first(&private->mem_rb); node; ) {
759 entry = rb_entry(node, struct kgsl_mem_entry, node);
760 node = rb_next(&entry->node);
761
762 rb_erase(&entry->node, &private->mem_rb);
Jordan Crouse00714012012-03-16 14:53:40 -0600763 kgsl_mem_entry_detach_process(entry);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700764 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700765 kgsl_mmu_putpagetable(private->pagetable);
766 kfree(private);
767unlock:
768 mutex_unlock(&kgsl_driver.process_mutex);
769}
770
771static int kgsl_release(struct inode *inodep, struct file *filep)
772{
773 int result = 0;
Jordan Crouse2db0af92011-08-08 16:05:09 -0600774 struct kgsl_device_private *dev_priv = filep->private_data;
775 struct kgsl_process_private *private = dev_priv->process_priv;
776 struct kgsl_device *device = dev_priv->device;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700777 struct kgsl_context *context;
778 int next = 0;
779
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700780 filep->private_data = NULL;
781
782 mutex_lock(&device->mutex);
783 kgsl_check_suspended(device);
784
785 while (1) {
Jordan Crouse2db0af92011-08-08 16:05:09 -0600786 context = idr_get_next(&device->context_idr, &next);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700787 if (context == NULL)
788 break;
789
Jeremy Gebben9ad86922012-05-08 15:33:23 -0600790 if (context->dev_priv == dev_priv)
791 kgsl_context_detach(context);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700792
793 next = next + 1;
794 }
Jeremy Gebben1384a6a2012-05-17 14:34:17 -0600795 /*
796 * Clean up any to-be-freed entries that belong to this
797 * process and this device. This is done after the context
798 * are destroyed to avoid possibly freeing memory while
799 * it is still in use by the GPU.
800 */
801 kgsl_cancel_events(device, dev_priv);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700802
803 device->open_count--;
804 if (device->open_count == 0) {
805 result = device->ftbl->stop(device);
Jeremy Gebben388c2972011-12-16 09:05:07 -0700806 kgsl_pwrctrl_set_state(device, KGSL_STATE_INIT);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700807 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700808
809 mutex_unlock(&device->mutex);
810 kfree(dev_priv);
811
812 kgsl_put_process_private(device, private);
813
814 pm_runtime_put(device->parentdev);
815 return result;
816}
817
818static int kgsl_open(struct inode *inodep, struct file *filep)
819{
820 int result;
821 struct kgsl_device_private *dev_priv;
822 struct kgsl_device *device;
823 unsigned int minor = iminor(inodep);
824
825 device = kgsl_get_minor(minor);
826 BUG_ON(device == NULL);
827
828 if (filep->f_flags & O_EXCL) {
829 KGSL_DRV_ERR(device, "O_EXCL not allowed\n");
830 return -EBUSY;
831 }
832
833 result = pm_runtime_get_sync(device->parentdev);
834 if (result < 0) {
835 KGSL_DRV_ERR(device,
836 "Runtime PM: Unable to wake up the device, rc = %d\n",
837 result);
838 return result;
839 }
840 result = 0;
841
842 dev_priv = kzalloc(sizeof(struct kgsl_device_private), GFP_KERNEL);
843 if (dev_priv == NULL) {
844 KGSL_DRV_ERR(device, "kzalloc failed(%d)\n",
845 sizeof(struct kgsl_device_private));
846 result = -ENOMEM;
847 goto err_pmruntime;
848 }
849
850 dev_priv->device = device;
851 filep->private_data = dev_priv;
852
853 /* Get file (per process) private struct */
854 dev_priv->process_priv = kgsl_get_process_private(dev_priv);
855 if (dev_priv->process_priv == NULL) {
856 result = -ENOMEM;
857 goto err_freedevpriv;
858 }
859
860 mutex_lock(&device->mutex);
861 kgsl_check_suspended(device);
862
863 if (device->open_count == 0) {
Carter Cooper7e7f02e2012-02-15 09:36:31 -0700864 kgsl_sharedmem_set(&device->memstore, 0, 0,
865 device->memstore.size);
866
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700867 result = device->ftbl->start(device, true);
868
869 if (result) {
870 mutex_unlock(&device->mutex);
871 goto err_putprocess;
872 }
Jeremy Gebben388c2972011-12-16 09:05:07 -0700873 kgsl_pwrctrl_set_state(device, KGSL_STATE_ACTIVE);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700874 }
875 device->open_count++;
876 mutex_unlock(&device->mutex);
877
878 KGSL_DRV_INFO(device, "Initialized %s: mmu=%s pagetable_count=%d\n",
879 device->name, kgsl_mmu_enabled() ? "on" : "off",
880 kgsl_pagetable_count);
881
882 return result;
883
884err_putprocess:
885 kgsl_put_process_private(device, dev_priv->process_priv);
886err_freedevpriv:
887 filep->private_data = NULL;
888 kfree(dev_priv);
889err_pmruntime:
890 pm_runtime_put(device->parentdev);
891 return result;
892}
893
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700894/*call with private->mem_lock locked */
895struct kgsl_mem_entry *
896kgsl_sharedmem_find_region(struct kgsl_process_private *private,
Jordan Crousec9559e42012-04-05 16:55:56 -0600897 unsigned int gpuaddr, size_t size)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700898{
Jordan Crousec9559e42012-04-05 16:55:56 -0600899 struct rb_node *node = private->mem_rb.rb_node;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700900
Jordan Crousee22e21d2012-07-23 14:34:06 -0600901 if (!kgsl_mmu_gpuaddr_in_range(gpuaddr))
902 return NULL;
903
Jordan Crousec9559e42012-04-05 16:55:56 -0600904 while (node != NULL) {
905 struct kgsl_mem_entry *entry;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700906
Jordan Crousec9559e42012-04-05 16:55:56 -0600907 entry = rb_entry(node, struct kgsl_mem_entry, node);
908
909
910 if (kgsl_gpuaddr_in_memdesc(&entry->memdesc, gpuaddr, size))
911 return entry;
912
913 if (gpuaddr < entry->memdesc.gpuaddr)
914 node = node->rb_left;
915 else if (gpuaddr >=
916 (entry->memdesc.gpuaddr + entry->memdesc.size))
917 node = node->rb_right;
918 else {
919 return NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700920 }
921 }
922
Jordan Crousec9559e42012-04-05 16:55:56 -0600923 return NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700924}
925EXPORT_SYMBOL(kgsl_sharedmem_find_region);
926
Jordan Crousec9559e42012-04-05 16:55:56 -0600927/*call with private->mem_lock locked */
928static inline struct kgsl_mem_entry *
929kgsl_sharedmem_find(struct kgsl_process_private *private, unsigned int gpuaddr)
930{
931 return kgsl_sharedmem_find_region(private, gpuaddr, 1);
932}
933
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700934/*call all ioctl sub functions with driver locked*/
935static long kgsl_ioctl_device_getproperty(struct kgsl_device_private *dev_priv,
936 unsigned int cmd, void *data)
937{
938 int result = 0;
939 struct kgsl_device_getproperty *param = data;
940
941 switch (param->type) {
942 case KGSL_PROP_VERSION:
943 {
944 struct kgsl_version version;
945 if (param->sizebytes != sizeof(version)) {
946 result = -EINVAL;
947 break;
948 }
949
950 version.drv_major = KGSL_VERSION_MAJOR;
951 version.drv_minor = KGSL_VERSION_MINOR;
952 version.dev_major = dev_priv->device->ver_major;
953 version.dev_minor = dev_priv->device->ver_minor;
954
955 if (copy_to_user(param->value, &version, sizeof(version)))
956 result = -EFAULT;
957
958 break;
959 }
Shubhraprakash Das2dfe5dd2012-02-10 13:49:53 -0700960 case KGSL_PROP_GPU_RESET_STAT:
961 {
962 /* Return reset status of given context and clear it */
963 uint32_t id;
964 struct kgsl_context *context;
965
966 if (param->sizebytes != sizeof(unsigned int)) {
967 result = -EINVAL;
968 break;
969 }
970 /* We expect the value passed in to contain the context id */
971 if (copy_from_user(&id, param->value,
972 sizeof(unsigned int))) {
973 result = -EFAULT;
974 break;
975 }
976 context = kgsl_find_context(dev_priv, id);
977 if (!context) {
978 result = -EINVAL;
979 break;
980 }
981 /*
982 * Copy the reset status to value which also serves as
983 * the out parameter
984 */
985 if (copy_to_user(param->value, &(context->reset_status),
986 sizeof(unsigned int))) {
987 result = -EFAULT;
988 break;
989 }
990 /* Clear reset status once its been queried */
991 context->reset_status = KGSL_CTX_STAT_NO_ERROR;
992 break;
993 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700994 default:
995 result = dev_priv->device->ftbl->getproperty(
996 dev_priv->device, param->type,
997 param->value, param->sizebytes);
998 }
999
1000
1001 return result;
1002}
1003
Jordan Crouseed7dd7f2012-03-29 13:16:02 -06001004static long kgsl_ioctl_device_setproperty(struct kgsl_device_private *dev_priv,
1005 unsigned int cmd, void *data)
1006{
1007 int result = 0;
1008 /* The getproperty struct is reused for setproperty too */
1009 struct kgsl_device_getproperty *param = data;
1010
1011 if (dev_priv->device->ftbl->setproperty)
1012 result = dev_priv->device->ftbl->setproperty(
1013 dev_priv->device, param->type,
1014 param->value, param->sizebytes);
1015
1016 return result;
1017}
1018
Carter Cooper7e7f02e2012-02-15 09:36:31 -07001019static long _device_waittimestamp(struct kgsl_device_private *dev_priv,
1020 struct kgsl_context *context,
1021 unsigned int timestamp,
1022 unsigned int timeout)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001023{
1024 int result = 0;
Jeremy Gebben4a3756c2012-05-08 16:51:43 -06001025 struct kgsl_device *device = dev_priv->device;
1026 unsigned int context_id = context ? context->id : KGSL_MEMSTORE_GLOBAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001027
Carter Cooper7e7f02e2012-02-15 09:36:31 -07001028 /* Set the active count so that suspend doesn't do the wrong thing */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001029
Jeremy Gebben4a3756c2012-05-08 16:51:43 -06001030 device->active_cnt++;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001031
Jeremy Gebben4a3756c2012-05-08 16:51:43 -06001032 trace_kgsl_waittimestamp_entry(device, context_id,
1033 kgsl_readtimestamp(device, context,
1034 KGSL_TIMESTAMP_RETIRED),
1035 timestamp, timeout);
Norman Geed7402ff2011-10-28 08:51:11 -06001036
Jeremy Gebben4a3756c2012-05-08 16:51:43 -06001037 result = device->ftbl->waittimestamp(dev_priv->device,
Carter Cooper7e7f02e2012-02-15 09:36:31 -07001038 context, timestamp, timeout);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001039
Jeremy Gebben4a3756c2012-05-08 16:51:43 -06001040 trace_kgsl_waittimestamp_exit(device,
1041 kgsl_readtimestamp(device, context,
1042 KGSL_TIMESTAMP_RETIRED),
1043 result);
Norman Geed7402ff2011-10-28 08:51:11 -06001044
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001045 /* Fire off any pending suspend operations that are in flight */
1046
1047 INIT_COMPLETION(dev_priv->device->suspend_gate);
1048 dev_priv->device->active_cnt--;
1049 complete(&dev_priv->device->suspend_gate);
1050
1051 return result;
1052}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001053
Carter Cooper7e7f02e2012-02-15 09:36:31 -07001054static long kgsl_ioctl_device_waittimestamp(struct kgsl_device_private
1055 *dev_priv, unsigned int cmd,
1056 void *data)
1057{
1058 struct kgsl_device_waittimestamp *param = data;
1059
Jeremy Gebben4a3756c2012-05-08 16:51:43 -06001060 return _device_waittimestamp(dev_priv, NULL,
Carter Cooper7e7f02e2012-02-15 09:36:31 -07001061 param->timestamp, param->timeout);
1062}
1063
1064static long kgsl_ioctl_device_waittimestamp_ctxtid(struct kgsl_device_private
1065 *dev_priv, unsigned int cmd,
1066 void *data)
1067{
1068 struct kgsl_device_waittimestamp_ctxtid *param = data;
1069 struct kgsl_context *context;
Jeremy Gebben9ad86922012-05-08 15:33:23 -06001070 int result;
Carter Cooper7e7f02e2012-02-15 09:36:31 -07001071
1072 context = kgsl_find_context(dev_priv, param->context_id);
1073 if (context == NULL) {
1074 KGSL_DRV_ERR(dev_priv->device, "invalid context_id %d\n",
1075 param->context_id);
1076 return -EINVAL;
1077 }
Jeremy Gebben9ad86922012-05-08 15:33:23 -06001078 /*
1079 * A reference count is needed here, because waittimestamp may
1080 * block with the device mutex unlocked and userspace could
1081 * request for the context to be destroyed during that time.
1082 */
1083 kgsl_context_get(context);
1084 result = _device_waittimestamp(dev_priv, context,
Carter Cooper7e7f02e2012-02-15 09:36:31 -07001085 param->timestamp, param->timeout);
Jeremy Gebben9ad86922012-05-08 15:33:23 -06001086 kgsl_context_put(context);
1087 return result;
Carter Cooper7e7f02e2012-02-15 09:36:31 -07001088}
1089
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001090static long kgsl_ioctl_rb_issueibcmds(struct kgsl_device_private *dev_priv,
1091 unsigned int cmd, void *data)
1092{
1093 int result = 0;
1094 struct kgsl_ringbuffer_issueibcmds *param = data;
1095 struct kgsl_ibdesc *ibdesc;
1096 struct kgsl_context *context;
1097
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001098 context = kgsl_find_context(dev_priv, param->drawctxt_id);
1099 if (context == NULL) {
1100 result = -EINVAL;
1101 KGSL_DRV_ERR(dev_priv->device,
Carter Cooper7e7f02e2012-02-15 09:36:31 -07001102 "invalid context_id %d\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001103 param->drawctxt_id);
1104 goto done;
1105 }
1106
1107 if (param->flags & KGSL_CONTEXT_SUBMIT_IB_LIST) {
1108 KGSL_DRV_INFO(dev_priv->device,
1109 "Using IB list mode for ib submission, numibs: %d\n",
1110 param->numibs);
1111 if (!param->numibs) {
1112 KGSL_DRV_ERR(dev_priv->device,
1113 "Invalid numibs as parameter: %d\n",
1114 param->numibs);
1115 result = -EINVAL;
1116 goto done;
1117 }
1118
Jordan Crouse834c8592012-07-24 10:06:35 -06001119 /*
1120 * Put a reasonable upper limit on the number of IBs that can be
1121 * submitted
1122 */
1123
1124 if (param->numibs > 10000) {
1125 KGSL_DRV_ERR(dev_priv->device,
1126 "Too many IBs submitted. count: %d max 10000\n",
1127 param->numibs);
1128 result = -EINVAL;
1129 goto done;
1130 }
1131
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001132 ibdesc = kzalloc(sizeof(struct kgsl_ibdesc) * param->numibs,
1133 GFP_KERNEL);
1134 if (!ibdesc) {
1135 KGSL_MEM_ERR(dev_priv->device,
1136 "kzalloc(%d) failed\n",
1137 sizeof(struct kgsl_ibdesc) * param->numibs);
1138 result = -ENOMEM;
1139 goto done;
1140 }
1141
1142 if (copy_from_user(ibdesc, (void *)param->ibdesc_addr,
1143 sizeof(struct kgsl_ibdesc) * param->numibs)) {
1144 result = -EFAULT;
1145 KGSL_DRV_ERR(dev_priv->device,
1146 "copy_from_user failed\n");
1147 goto free_ibdesc;
1148 }
1149 } else {
1150 KGSL_DRV_INFO(dev_priv->device,
1151 "Using single IB submission mode for ib submission\n");
1152 /* If user space driver is still using the old mode of
1153 * submitting single ib then we need to support that as well */
1154 ibdesc = kzalloc(sizeof(struct kgsl_ibdesc), GFP_KERNEL);
1155 if (!ibdesc) {
1156 KGSL_MEM_ERR(dev_priv->device,
1157 "kzalloc(%d) failed\n",
1158 sizeof(struct kgsl_ibdesc));
1159 result = -ENOMEM;
1160 goto done;
1161 }
1162 ibdesc[0].gpuaddr = param->ibdesc_addr;
1163 ibdesc[0].sizedwords = param->numibs;
1164 param->numibs = 1;
1165 }
1166
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001167 result = dev_priv->device->ftbl->issueibcmds(dev_priv,
1168 context,
1169 ibdesc,
1170 param->numibs,
1171 &param->timestamp,
1172 param->flags);
1173
Jeremy Gebben4a3756c2012-05-08 16:51:43 -06001174 trace_kgsl_issueibcmds(dev_priv->device, param, ibdesc, result);
Wei Zouc8c01632012-03-24 17:27:26 -07001175
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001176free_ibdesc:
1177 kfree(ibdesc);
1178done:
1179
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001180 return result;
1181}
1182
Carter Cooper7e7f02e2012-02-15 09:36:31 -07001183static long _cmdstream_readtimestamp(struct kgsl_device_private *dev_priv,
1184 struct kgsl_context *context, unsigned int type,
1185 unsigned int *timestamp)
1186{
Jeremy Gebben731dac52012-05-10 11:13:42 -06001187 *timestamp = kgsl_readtimestamp(dev_priv->device, context, type);
Carter Cooper7e7f02e2012-02-15 09:36:31 -07001188
1189 trace_kgsl_readtimestamp(dev_priv->device,
1190 context ? context->id : KGSL_MEMSTORE_GLOBAL,
1191 type, *timestamp);
1192
1193 return 0;
1194}
1195
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001196static long kgsl_ioctl_cmdstream_readtimestamp(struct kgsl_device_private
1197 *dev_priv, unsigned int cmd,
1198 void *data)
1199{
1200 struct kgsl_cmdstream_readtimestamp *param = data;
1201
Carter Cooper7e7f02e2012-02-15 09:36:31 -07001202 return _cmdstream_readtimestamp(dev_priv, NULL,
1203 param->type, &param->timestamp);
1204}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001205
Carter Cooper7e7f02e2012-02-15 09:36:31 -07001206static long kgsl_ioctl_cmdstream_readtimestamp_ctxtid(struct kgsl_device_private
1207 *dev_priv, unsigned int cmd,
1208 void *data)
1209{
1210 struct kgsl_cmdstream_readtimestamp_ctxtid *param = data;
1211 struct kgsl_context *context;
Norman Geed7402ff2011-10-28 08:51:11 -06001212
Carter Cooper7e7f02e2012-02-15 09:36:31 -07001213 context = kgsl_find_context(dev_priv, param->context_id);
1214 if (context == NULL) {
1215 KGSL_DRV_ERR(dev_priv->device, "invalid context_id %d\n",
1216 param->context_id);
1217 return -EINVAL;
1218 }
1219
1220 return _cmdstream_readtimestamp(dev_priv, context,
1221 param->type, &param->timestamp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001222}
1223
Jeremy Gebbenc81a3c62012-02-07 16:10:23 -07001224static void kgsl_freemem_event_cb(struct kgsl_device *device,
Carter Cooper7e7f02e2012-02-15 09:36:31 -07001225 void *priv, u32 id, u32 timestamp)
Jeremy Gebbenc81a3c62012-02-07 16:10:23 -07001226{
1227 struct kgsl_mem_entry *entry = priv;
1228 spin_lock(&entry->priv->mem_lock);
Jordan Crousec9559e42012-04-05 16:55:56 -06001229 rb_erase(&entry->node, &entry->priv->mem_rb);
Jeremy Gebbenc81a3c62012-02-07 16:10:23 -07001230 spin_unlock(&entry->priv->mem_lock);
Jeremy Gebben4a3756c2012-05-08 16:51:43 -06001231 trace_kgsl_mem_timestamp_free(device, entry, id, timestamp, 0);
Jordan Crouse00714012012-03-16 14:53:40 -06001232 kgsl_mem_entry_detach_process(entry);
Jeremy Gebbenc81a3c62012-02-07 16:10:23 -07001233}
1234
Carter Cooper7e7f02e2012-02-15 09:36:31 -07001235static long _cmdstream_freememontimestamp(struct kgsl_device_private *dev_priv,
1236 unsigned int gpuaddr, struct kgsl_context *context,
1237 unsigned int timestamp, unsigned int type)
1238{
1239 int result = 0;
1240 struct kgsl_mem_entry *entry = NULL;
1241 struct kgsl_device *device = dev_priv->device;
Carter Cooper7e7f02e2012-02-15 09:36:31 -07001242 unsigned int context_id = context ? context->id : KGSL_MEMSTORE_GLOBAL;
1243
1244 spin_lock(&dev_priv->process_priv->mem_lock);
1245 entry = kgsl_sharedmem_find(dev_priv->process_priv, gpuaddr);
1246 spin_unlock(&dev_priv->process_priv->mem_lock);
1247
Jeremy Gebben4a3756c2012-05-08 16:51:43 -06001248 if (!entry) {
Carter Cooper7e7f02e2012-02-15 09:36:31 -07001249 KGSL_DRV_ERR(dev_priv->device,
Jeremy Gebben4a3756c2012-05-08 16:51:43 -06001250 "invalid gpuaddr %08x\n", gpuaddr);
Carter Cooper7e7f02e2012-02-15 09:36:31 -07001251 result = -EINVAL;
Jeremy Gebben4a3756c2012-05-08 16:51:43 -06001252 goto done;
Carter Cooper7e7f02e2012-02-15 09:36:31 -07001253 }
Jeremy Gebben4a3756c2012-05-08 16:51:43 -06001254 trace_kgsl_mem_timestamp_queue(device, entry, context_id,
1255 kgsl_readtimestamp(device, context,
1256 KGSL_TIMESTAMP_RETIRED),
1257 timestamp);
1258 result = kgsl_add_event(dev_priv->device, context_id, timestamp,
1259 kgsl_freemem_event_cb, entry, dev_priv);
1260done:
Carter Cooper7e7f02e2012-02-15 09:36:31 -07001261 return result;
1262}
1263
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001264static long kgsl_ioctl_cmdstream_freememontimestamp(struct kgsl_device_private
1265 *dev_priv, unsigned int cmd,
1266 void *data)
1267{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001268 struct kgsl_cmdstream_freememontimestamp *param = data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001269
Carter Cooper7e7f02e2012-02-15 09:36:31 -07001270 return _cmdstream_freememontimestamp(dev_priv, param->gpuaddr,
1271 NULL, param->timestamp, param->type);
1272}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001273
Carter Cooper7e7f02e2012-02-15 09:36:31 -07001274static long kgsl_ioctl_cmdstream_freememontimestamp_ctxtid(
1275 struct kgsl_device_private
1276 *dev_priv, unsigned int cmd,
1277 void *data)
1278{
1279 struct kgsl_cmdstream_freememontimestamp_ctxtid *param = data;
1280 struct kgsl_context *context;
Jeremy Gebbena5859272012-03-01 12:46:28 -07001281
Carter Cooper7e7f02e2012-02-15 09:36:31 -07001282 context = kgsl_find_context(dev_priv, param->context_id);
1283 if (context == NULL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001284 KGSL_DRV_ERR(dev_priv->device,
Carter Cooper7e7f02e2012-02-15 09:36:31 -07001285 "invalid drawctxt context_id %d\n", param->context_id);
1286 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001287 }
1288
Carter Cooper7e7f02e2012-02-15 09:36:31 -07001289 return _cmdstream_freememontimestamp(dev_priv, param->gpuaddr,
1290 context, param->timestamp, param->type);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001291}
1292
1293static long kgsl_ioctl_drawctxt_create(struct kgsl_device_private *dev_priv,
1294 unsigned int cmd, void *data)
1295{
1296 int result = 0;
1297 struct kgsl_drawctxt_create *param = data;
1298 struct kgsl_context *context = NULL;
1299
1300 context = kgsl_create_context(dev_priv);
1301
1302 if (context == NULL) {
1303 result = -ENOMEM;
1304 goto done;
1305 }
1306
Jeremy Gebben4a3756c2012-05-08 16:51:43 -06001307 if (dev_priv->device->ftbl->drawctxt_create) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001308 result = dev_priv->device->ftbl->drawctxt_create(
1309 dev_priv->device, dev_priv->process_priv->pagetable,
1310 context, param->flags);
Jeremy Gebben4a3756c2012-05-08 16:51:43 -06001311 if (result)
1312 goto done;
1313 }
1314 trace_kgsl_context_create(dev_priv->device, context, param->flags);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001315 param->drawctxt_id = context->id;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001316done:
1317 if (result && context)
Jeremy Gebben9ad86922012-05-08 15:33:23 -06001318 kgsl_context_detach(context);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001319
1320 return result;
1321}
1322
1323static long kgsl_ioctl_drawctxt_destroy(struct kgsl_device_private *dev_priv,
1324 unsigned int cmd, void *data)
1325{
1326 int result = 0;
1327 struct kgsl_drawctxt_destroy *param = data;
1328 struct kgsl_context *context;
1329
1330 context = kgsl_find_context(dev_priv, param->drawctxt_id);
1331
1332 if (context == NULL) {
1333 result = -EINVAL;
1334 goto done;
1335 }
1336
Jeremy Gebben9ad86922012-05-08 15:33:23 -06001337 kgsl_context_detach(context);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001338done:
1339 return result;
1340}
1341
1342static long kgsl_ioctl_sharedmem_free(struct kgsl_device_private *dev_priv,
1343 unsigned int cmd, void *data)
1344{
1345 int result = 0;
1346 struct kgsl_sharedmem_free *param = data;
1347 struct kgsl_process_private *private = dev_priv->process_priv;
1348 struct kgsl_mem_entry *entry = NULL;
1349
1350 spin_lock(&private->mem_lock);
1351 entry = kgsl_sharedmem_find(private, param->gpuaddr);
1352 if (entry)
Jordan Crousec9559e42012-04-05 16:55:56 -06001353 rb_erase(&entry->node, &private->mem_rb);
1354
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001355 spin_unlock(&private->mem_lock);
1356
1357 if (entry) {
Jeremy Gebbena5859272012-03-01 12:46:28 -07001358 trace_kgsl_mem_free(entry);
Jordan Crouse00714012012-03-16 14:53:40 -06001359 kgsl_mem_entry_detach_process(entry);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001360 } else {
1361 KGSL_CORE_ERR("invalid gpuaddr %08x\n", param->gpuaddr);
1362 result = -EINVAL;
1363 }
1364
1365 return result;
1366}
1367
1368static struct vm_area_struct *kgsl_get_vma_from_start_addr(unsigned int addr)
1369{
1370 struct vm_area_struct *vma;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001371
1372 down_read(&current->mm->mmap_sem);
1373 vma = find_vma(current->mm, addr);
1374 up_read(&current->mm->mmap_sem);
Jordan Crouse2c542b62011-07-26 08:30:20 -06001375 if (!vma)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001376 KGSL_CORE_ERR("find_vma(%x) failed\n", addr);
Jordan Crouse2c542b62011-07-26 08:30:20 -06001377
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001378 return vma;
1379}
1380
1381static long
1382kgsl_ioctl_sharedmem_from_vmalloc(struct kgsl_device_private *dev_priv,
1383 unsigned int cmd, void *data)
1384{
1385 int result = 0, len = 0;
1386 struct kgsl_process_private *private = dev_priv->process_priv;
1387 struct kgsl_sharedmem_from_vmalloc *param = data;
1388 struct kgsl_mem_entry *entry = NULL;
1389 struct vm_area_struct *vma;
1390
Harsh Vardhan Dwivedia9eb7cb2012-03-26 15:21:38 -06001391 KGSL_DEV_ERR_ONCE(dev_priv->device, "IOCTL_KGSL_SHAREDMEM_FROM_VMALLOC"
1392 " is deprecated\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001393 if (!kgsl_mmu_enabled())
1394 return -ENODEV;
1395
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001396 if (!param->hostptr) {
1397 KGSL_CORE_ERR("invalid hostptr %x\n", param->hostptr);
1398 result = -EINVAL;
1399 goto error;
1400 }
1401
1402 vma = kgsl_get_vma_from_start_addr(param->hostptr);
1403 if (!vma) {
1404 result = -EINVAL;
1405 goto error;
1406 }
Jordan Crouse2c542b62011-07-26 08:30:20 -06001407
1408 /*
1409 * If the user specified a length, use it, otherwise try to
1410 * infer the length if the vma region
1411 */
1412 if (param->gpuaddr != 0) {
1413 len = param->gpuaddr;
1414 } else {
1415 /*
1416 * For this to work, we have to assume the VMA region is only
1417 * for this single allocation. If it isn't, then bail out
1418 */
1419 if (vma->vm_pgoff || (param->hostptr != vma->vm_start)) {
1420 KGSL_CORE_ERR("VMA region does not match hostaddr\n");
1421 result = -EINVAL;
1422 goto error;
1423 }
1424
1425 len = vma->vm_end - vma->vm_start;
1426 }
1427
1428 /* Make sure it fits */
1429 if (len == 0 || param->hostptr + len > vma->vm_end) {
1430 KGSL_CORE_ERR("Invalid memory allocation length %d\n", len);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001431 result = -EINVAL;
1432 goto error;
1433 }
1434
1435 entry = kgsl_mem_entry_create();
1436 if (entry == NULL) {
1437 result = -ENOMEM;
1438 goto error;
1439 }
1440
Harsh Vardhan Dwivedif99c2632012-03-15 14:17:11 -06001441 result = kgsl_sharedmem_page_alloc_user(&entry->memdesc,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001442 private->pagetable, len,
1443 param->flags);
1444 if (result != 0)
1445 goto error_free_entry;
1446
1447 vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
1448
Harsh Vardhan Dwivedi8cb835b2012-03-29 17:23:11 -06001449 result = kgsl_sharedmem_map_vma(vma, &entry->memdesc);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001450 if (result) {
Harsh Vardhan Dwivedi8cb835b2012-03-29 17:23:11 -06001451 KGSL_CORE_ERR("kgsl_sharedmem_map_vma failed: %d\n", result);
Harsh Vardhan Dwivedif99c2632012-03-15 14:17:11 -06001452 goto error_free_alloc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001453 }
1454
1455 param->gpuaddr = entry->memdesc.gpuaddr;
1456
Jordan Crouse1b897cf2011-10-12 16:57:48 -06001457 entry->memtype = KGSL_MEM_ENTRY_KERNEL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001458
1459 kgsl_mem_entry_attach_process(entry, private);
1460
Jeremy Gebbena5859272012-03-01 12:46:28 -07001461 trace_kgsl_mem_alloc(entry);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001462 /* Process specific statistics */
Jordan Crouse1b897cf2011-10-12 16:57:48 -06001463 kgsl_process_add_stats(private, entry->memtype, len);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001464
1465 kgsl_check_idle(dev_priv->device);
1466 return 0;
1467
Harsh Vardhan Dwivedif99c2632012-03-15 14:17:11 -06001468error_free_alloc:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001469 kgsl_sharedmem_free(&entry->memdesc);
1470
1471error_free_entry:
1472 kfree(entry);
1473
1474error:
1475 kgsl_check_idle(dev_priv->device);
1476 return result;
1477}
1478
1479static inline int _check_region(unsigned long start, unsigned long size,
1480 uint64_t len)
1481{
1482 uint64_t end = ((uint64_t) start) + size;
1483 return (end > len);
1484}
1485
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001486static int kgsl_get_phys_file(int fd, unsigned long *start, unsigned long *len,
1487 unsigned long *vstart, struct file **filep)
1488{
1489 struct file *fbfile;
1490 int ret = 0;
1491 dev_t rdev;
1492 struct fb_info *info;
1493
1494 *filep = NULL;
Jordan Crousefd978432011-09-02 14:34:32 -06001495#ifdef CONFIG_ANDROID_PMEM
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001496 if (!get_pmem_file(fd, start, vstart, len, filep))
1497 return 0;
Jordan Crousefd978432011-09-02 14:34:32 -06001498#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001499
1500 fbfile = fget(fd);
1501 if (fbfile == NULL) {
1502 KGSL_CORE_ERR("fget_light failed\n");
1503 return -1;
1504 }
1505
1506 rdev = fbfile->f_dentry->d_inode->i_rdev;
1507 info = MAJOR(rdev) == FB_MAJOR ? registered_fb[MINOR(rdev)] : NULL;
1508 if (info) {
1509 *start = info->fix.smem_start;
1510 *len = info->fix.smem_len;
1511 *vstart = (unsigned long)__va(info->fix.smem_start);
1512 ret = 0;
1513 } else {
1514 KGSL_CORE_ERR("framebuffer minor %d not found\n",
1515 MINOR(rdev));
1516 ret = -1;
1517 }
1518
1519 fput(fbfile);
1520
1521 return ret;
1522}
1523
1524static int kgsl_setup_phys_file(struct kgsl_mem_entry *entry,
1525 struct kgsl_pagetable *pagetable,
1526 unsigned int fd, unsigned int offset,
1527 size_t size)
1528{
1529 int ret;
1530 unsigned long phys, virt, len;
1531 struct file *filep;
1532
1533 ret = kgsl_get_phys_file(fd, &phys, &len, &virt, &filep);
1534 if (ret)
1535 return ret;
1536
Wei Zou4061c0b2011-07-08 10:24:22 -07001537 if (phys == 0) {
1538 ret = -EINVAL;
1539 goto err;
1540 }
1541
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001542 if (offset >= len) {
1543 ret = -EINVAL;
1544 goto err;
1545 }
1546
1547 if (size == 0)
1548 size = len;
1549
1550 /* Adjust the size of the region to account for the offset */
1551 size += offset & ~PAGE_MASK;
1552
1553 size = ALIGN(size, PAGE_SIZE);
1554
1555 if (_check_region(offset & PAGE_MASK, size, len)) {
1556 KGSL_CORE_ERR("Offset (%ld) + size (%d) is larger"
1557 "than pmem region length %ld\n",
1558 offset & PAGE_MASK, size, len);
1559 ret = -EINVAL;
1560 goto err;
1561
1562 }
1563
Jordan Crouse1b897cf2011-10-12 16:57:48 -06001564 entry->priv_data = filep;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001565
1566 entry->memdesc.pagetable = pagetable;
1567 entry->memdesc.size = size;
1568 entry->memdesc.physaddr = phys + (offset & PAGE_MASK);
1569 entry->memdesc.hostptr = (void *) (virt + (offset & PAGE_MASK));
Jordan Croused17e9aa2011-10-12 16:57:48 -06001570
1571 ret = memdesc_sg_phys(&entry->memdesc,
1572 phys + (offset & PAGE_MASK), size);
1573 if (ret)
1574 goto err;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001575
1576 return 0;
1577err:
Jordan Crousefd978432011-09-02 14:34:32 -06001578#ifdef CONFIG_ANDROID_PMEM
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001579 put_pmem_file(filep);
Jordan Crousefd978432011-09-02 14:34:32 -06001580#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001581 return ret;
1582}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001583
Jordan Croused17e9aa2011-10-12 16:57:48 -06001584static int memdesc_sg_virt(struct kgsl_memdesc *memdesc,
1585 void *addr, int size)
1586{
1587 int i;
1588 int sglen = PAGE_ALIGN(size) / PAGE_SIZE;
1589 unsigned long paddr = (unsigned long) addr;
1590
Jordan Crousea652a072012-04-06 16:26:33 -06001591 memdesc->sg = kgsl_sg_alloc(sglen);
1592
Jordan Croused17e9aa2011-10-12 16:57:48 -06001593 if (memdesc->sg == NULL)
1594 return -ENOMEM;
1595
1596 memdesc->sglen = sglen;
1597 sg_init_table(memdesc->sg, sglen);
1598
1599 spin_lock(&current->mm->page_table_lock);
1600
1601 for (i = 0; i < sglen; i++, paddr += PAGE_SIZE) {
1602 struct page *page;
1603 pmd_t *ppmd;
1604 pte_t *ppte;
1605 pgd_t *ppgd = pgd_offset(current->mm, paddr);
1606
1607 if (pgd_none(*ppgd) || pgd_bad(*ppgd))
1608 goto err;
1609
Steve Mucklef132c6c2012-06-06 18:30:57 -07001610 ppmd = pmd_offset(pud_offset(ppgd, paddr), paddr);
Jordan Croused17e9aa2011-10-12 16:57:48 -06001611 if (pmd_none(*ppmd) || pmd_bad(*ppmd))
1612 goto err;
1613
1614 ppte = pte_offset_map(ppmd, paddr);
1615 if (ppte == NULL)
1616 goto err;
1617
1618 page = pfn_to_page(pte_pfn(*ppte));
1619 if (!page)
1620 goto err;
1621
1622 sg_set_page(&memdesc->sg[i], page, PAGE_SIZE, 0);
1623 pte_unmap(ppte);
1624 }
1625
1626 spin_unlock(&current->mm->page_table_lock);
1627
1628 return 0;
1629
1630err:
1631 spin_unlock(&current->mm->page_table_lock);
Jordan Crousea652a072012-04-06 16:26:33 -06001632 kgsl_sg_free(memdesc->sg, sglen);
Jordan Croused17e9aa2011-10-12 16:57:48 -06001633 memdesc->sg = NULL;
1634
1635 return -EINVAL;
1636}
1637
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001638static int kgsl_setup_hostptr(struct kgsl_mem_entry *entry,
1639 struct kgsl_pagetable *pagetable,
1640 void *hostptr, unsigned int offset,
1641 size_t size)
1642{
1643 struct vm_area_struct *vma;
1644 unsigned int len;
1645
1646 down_read(&current->mm->mmap_sem);
1647 vma = find_vma(current->mm, (unsigned int) hostptr);
1648 up_read(&current->mm->mmap_sem);
1649
1650 if (!vma) {
1651 KGSL_CORE_ERR("find_vma(%p) failed\n", hostptr);
1652 return -EINVAL;
1653 }
1654
1655 /* We don't necessarily start at vma->vm_start */
1656 len = vma->vm_end - (unsigned long) hostptr;
1657
1658 if (offset >= len)
1659 return -EINVAL;
1660
1661 if (!KGSL_IS_PAGE_ALIGNED((unsigned long) hostptr) ||
1662 !KGSL_IS_PAGE_ALIGNED(len)) {
1663 KGSL_CORE_ERR("user address len(%u)"
1664 "and start(%p) must be page"
1665 "aligned\n", len, hostptr);
1666 return -EINVAL;
1667 }
1668
1669 if (size == 0)
1670 size = len;
1671
1672 /* Adjust the size of the region to account for the offset */
1673 size += offset & ~PAGE_MASK;
1674
1675 size = ALIGN(size, PAGE_SIZE);
1676
1677 if (_check_region(offset & PAGE_MASK, size, len)) {
1678 KGSL_CORE_ERR("Offset (%ld) + size (%d) is larger"
1679 "than region length %d\n",
1680 offset & PAGE_MASK, size, len);
1681 return -EINVAL;
1682 }
1683
1684 entry->memdesc.pagetable = pagetable;
1685 entry->memdesc.size = size;
1686 entry->memdesc.hostptr = hostptr + (offset & PAGE_MASK);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001687
Jordan Croused17e9aa2011-10-12 16:57:48 -06001688 return memdesc_sg_virt(&entry->memdesc,
1689 hostptr + (offset & PAGE_MASK), size);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001690}
1691
1692#ifdef CONFIG_ASHMEM
1693static int kgsl_setup_ashmem(struct kgsl_mem_entry *entry,
1694 struct kgsl_pagetable *pagetable,
1695 int fd, void *hostptr, size_t size)
1696{
1697 int ret;
1698 struct vm_area_struct *vma;
1699 struct file *filep, *vmfile;
1700 unsigned long len;
Jordan Crouse2c542b62011-07-26 08:30:20 -06001701 unsigned int hostaddr = (unsigned int) hostptr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001702
Jordan Crouse2c542b62011-07-26 08:30:20 -06001703 vma = kgsl_get_vma_from_start_addr(hostaddr);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001704 if (vma == NULL)
1705 return -EINVAL;
1706
Jordan Crouse2c542b62011-07-26 08:30:20 -06001707 if (vma->vm_pgoff || vma->vm_start != hostaddr) {
1708 KGSL_CORE_ERR("Invalid vma region\n");
1709 return -EINVAL;
1710 }
1711
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001712 len = vma->vm_end - vma->vm_start;
1713
1714 if (size == 0)
1715 size = len;
1716
1717 if (size != len) {
1718 KGSL_CORE_ERR("Invalid size %d for vma region %p\n",
1719 size, hostptr);
1720 return -EINVAL;
1721 }
1722
1723 ret = get_ashmem_file(fd, &filep, &vmfile, &len);
1724
1725 if (ret) {
1726 KGSL_CORE_ERR("get_ashmem_file failed\n");
1727 return ret;
1728 }
1729
1730 if (vmfile != vma->vm_file) {
1731 KGSL_CORE_ERR("ashmem shmem file does not match vma\n");
1732 ret = -EINVAL;
1733 goto err;
1734 }
1735
Jordan Crouse1b897cf2011-10-12 16:57:48 -06001736 entry->priv_data = filep;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001737 entry->memdesc.pagetable = pagetable;
1738 entry->memdesc.size = ALIGN(size, PAGE_SIZE);
1739 entry->memdesc.hostptr = hostptr;
Jordan Croused17e9aa2011-10-12 16:57:48 -06001740
1741 ret = memdesc_sg_virt(&entry->memdesc, hostptr, size);
1742 if (ret)
1743 goto err;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001744
1745 return 0;
1746
1747err:
1748 put_ashmem_file(filep);
1749 return ret;
1750}
1751#else
1752static int kgsl_setup_ashmem(struct kgsl_mem_entry *entry,
1753 struct kgsl_pagetable *pagetable,
1754 int fd, void *hostptr, size_t size)
1755{
1756 return -EINVAL;
1757}
1758#endif
1759
Jordan Crouse8eab35a2011-10-12 16:57:48 -06001760static int kgsl_setup_ion(struct kgsl_mem_entry *entry,
1761 struct kgsl_pagetable *pagetable, int fd)
1762{
1763 struct ion_handle *handle;
1764 struct scatterlist *s;
Laura Abbottb14ed962012-01-30 14:18:08 -08001765 struct sg_table *sg_table;
Jordan Crouse8eab35a2011-10-12 16:57:48 -06001766
Harsh Vardhan Dwivedif48af7f2012-04-13 12:50:44 -06001767 if (IS_ERR_OR_NULL(kgsl_ion_client))
1768 return -ENODEV;
Jordan Crouse8eab35a2011-10-12 16:57:48 -06001769
Laura Abbottb14ed962012-01-30 14:18:08 -08001770 handle = ion_import_dma_buf(kgsl_ion_client, fd);
Jordan Crouse8eab35a2011-10-12 16:57:48 -06001771 if (IS_ERR_OR_NULL(handle))
1772 return PTR_ERR(handle);
1773
1774 entry->memtype = KGSL_MEM_ENTRY_ION;
1775 entry->priv_data = handle;
1776 entry->memdesc.pagetable = pagetable;
1777 entry->memdesc.size = 0;
1778
Laura Abbottb14ed962012-01-30 14:18:08 -08001779 sg_table = ion_sg_table(kgsl_ion_client, handle);
1780
1781 if (IS_ERR_OR_NULL(sg_table))
Jordan Crouse8eab35a2011-10-12 16:57:48 -06001782 goto err;
1783
Laura Abbottb14ed962012-01-30 14:18:08 -08001784 entry->memdesc.sg = sg_table->sgl;
Jordan Crouse8eab35a2011-10-12 16:57:48 -06001785
1786 /* Calculate the size of the memdesc from the sglist */
1787
1788 entry->memdesc.sglen = 0;
1789
1790 for (s = entry->memdesc.sg; s != NULL; s = sg_next(s)) {
1791 entry->memdesc.size += s->length;
1792 entry->memdesc.sglen++;
1793 }
1794
1795 return 0;
1796err:
1797 ion_free(kgsl_ion_client, handle);
1798 return -ENOMEM;
1799}
1800
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001801static long kgsl_ioctl_map_user_mem(struct kgsl_device_private *dev_priv,
1802 unsigned int cmd, void *data)
1803{
1804 int result = -EINVAL;
1805 struct kgsl_map_user_mem *param = data;
1806 struct kgsl_mem_entry *entry = NULL;
1807 struct kgsl_process_private *private = dev_priv->process_priv;
Jason848741a2011-07-12 10:24:25 -07001808 enum kgsl_user_mem_type memtype;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001809
1810 entry = kgsl_mem_entry_create();
1811
1812 if (entry == NULL)
1813 return -ENOMEM;
1814
Jason848741a2011-07-12 10:24:25 -07001815 if (_IOC_SIZE(cmd) == sizeof(struct kgsl_sharedmem_from_pmem))
1816 memtype = KGSL_USER_MEM_TYPE_PMEM;
1817 else
1818 memtype = param->memtype;
1819
1820 switch (memtype) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001821 case KGSL_USER_MEM_TYPE_PMEM:
1822 if (param->fd == 0 || param->len == 0)
1823 break;
1824
1825 result = kgsl_setup_phys_file(entry, private->pagetable,
1826 param->fd, param->offset,
1827 param->len);
Jordan Crouse1b897cf2011-10-12 16:57:48 -06001828 entry->memtype = KGSL_MEM_ENTRY_PMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001829 break;
1830
1831 case KGSL_USER_MEM_TYPE_ADDR:
Harsh Vardhan Dwivedia9eb7cb2012-03-26 15:21:38 -06001832 KGSL_DEV_ERR_ONCE(dev_priv->device, "User mem type "
1833 "KGSL_USER_MEM_TYPE_ADDR is deprecated\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001834 if (!kgsl_mmu_enabled()) {
1835 KGSL_DRV_ERR(dev_priv->device,
1836 "Cannot map paged memory with the "
1837 "MMU disabled\n");
1838 break;
1839 }
1840
1841 if (param->hostptr == 0)
1842 break;
1843
1844 result = kgsl_setup_hostptr(entry, private->pagetable,
1845 (void *) param->hostptr,
1846 param->offset, param->len);
Jordan Crouse1b897cf2011-10-12 16:57:48 -06001847 entry->memtype = KGSL_MEM_ENTRY_USER;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001848 break;
1849
1850 case KGSL_USER_MEM_TYPE_ASHMEM:
1851 if (!kgsl_mmu_enabled()) {
1852 KGSL_DRV_ERR(dev_priv->device,
1853 "Cannot map paged memory with the "
1854 "MMU disabled\n");
1855 break;
1856 }
1857
1858 if (param->hostptr == 0)
1859 break;
1860
1861 result = kgsl_setup_ashmem(entry, private->pagetable,
1862 param->fd, (void *) param->hostptr,
1863 param->len);
Jordan Crouse1b897cf2011-10-12 16:57:48 -06001864
1865 entry->memtype = KGSL_MEM_ENTRY_ASHMEM;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001866 break;
Jordan Crouse8eab35a2011-10-12 16:57:48 -06001867 case KGSL_USER_MEM_TYPE_ION:
1868 result = kgsl_setup_ion(entry, private->pagetable,
1869 param->fd);
1870 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001871 default:
Jason848741a2011-07-12 10:24:25 -07001872 KGSL_CORE_ERR("Invalid memory type: %x\n", memtype);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001873 break;
1874 }
1875
1876 if (result)
1877 goto error;
1878
1879 result = kgsl_mmu_map(private->pagetable,
1880 &entry->memdesc,
1881 GSL_PT_PAGE_RV | GSL_PT_PAGE_WV);
1882
1883 if (result)
1884 goto error_put_file_ptr;
1885
1886 /* Adjust the returned value for a non 4k aligned offset */
1887 param->gpuaddr = entry->memdesc.gpuaddr + (param->offset & ~PAGE_MASK);
1888
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001889 KGSL_STATS_ADD(param->len, kgsl_driver.stats.mapped,
Jordan Crouse1b897cf2011-10-12 16:57:48 -06001890 kgsl_driver.stats.mapped_max);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001891
Jordan Crouse1b897cf2011-10-12 16:57:48 -06001892 kgsl_process_add_stats(private, entry->memtype, param->len);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001893
1894 kgsl_mem_entry_attach_process(entry, private);
Jeremy Gebbena5859272012-03-01 12:46:28 -07001895 trace_kgsl_mem_map(entry, param->fd);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001896
1897 kgsl_check_idle(dev_priv->device);
1898 return result;
1899
Jeremy Gebben53d4dd02012-05-07 15:42:00 -06001900error_put_file_ptr:
1901 switch (entry->memtype) {
1902 case KGSL_MEM_ENTRY_PMEM:
1903 case KGSL_MEM_ENTRY_ASHMEM:
1904 if (entry->priv_data)
1905 fput(entry->priv_data);
1906 break;
1907 case KGSL_MEM_ENTRY_ION:
Jeremy Gebben53d4dd02012-05-07 15:42:00 -06001908 ion_free(kgsl_ion_client, entry->priv_data);
1909 break;
1910 default:
1911 break;
1912 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001913error:
1914 kfree(entry);
1915 kgsl_check_idle(dev_priv->device);
1916 return result;
1917}
1918
1919/*This function flushes a graphics memory allocation from CPU cache
1920 *when caching is enabled with MMU*/
1921static long
1922kgsl_ioctl_sharedmem_flush_cache(struct kgsl_device_private *dev_priv,
1923 unsigned int cmd, void *data)
1924{
1925 int result = 0;
1926 struct kgsl_mem_entry *entry;
1927 struct kgsl_sharedmem_free *param = data;
1928 struct kgsl_process_private *private = dev_priv->process_priv;
1929
1930 spin_lock(&private->mem_lock);
1931 entry = kgsl_sharedmem_find(private, param->gpuaddr);
1932 if (!entry) {
1933 KGSL_CORE_ERR("invalid gpuaddr %08x\n", param->gpuaddr);
1934 result = -EINVAL;
Jeremy Gebben690f9d12011-08-08 16:33:49 -06001935 goto done;
1936 }
Jeremy Gebben690f9d12011-08-08 16:33:49 -06001937 if (!entry->memdesc.hostptr) {
1938 KGSL_CORE_ERR("invalid hostptr with gpuaddr %08x\n",
1939 param->gpuaddr);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001940 goto done;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001941 }
Jeremy Gebben690f9d12011-08-08 16:33:49 -06001942
1943 kgsl_cache_range_op(&entry->memdesc, KGSL_CACHE_OP_CLEAN);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001944done:
Jeremy Gebben690f9d12011-08-08 16:33:49 -06001945 spin_unlock(&private->mem_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001946 return result;
1947}
1948
1949static long
1950kgsl_ioctl_gpumem_alloc(struct kgsl_device_private *dev_priv,
1951 unsigned int cmd, void *data)
1952{
1953 struct kgsl_process_private *private = dev_priv->process_priv;
1954 struct kgsl_gpumem_alloc *param = data;
1955 struct kgsl_mem_entry *entry;
1956 int result;
1957
1958 entry = kgsl_mem_entry_create();
1959 if (entry == NULL)
1960 return -ENOMEM;
1961
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001962 result = kgsl_allocate_user(&entry->memdesc, private->pagetable,
1963 param->size, param->flags);
1964
1965 if (result == 0) {
Jordan Crouse1b897cf2011-10-12 16:57:48 -06001966 entry->memtype = KGSL_MEM_ENTRY_KERNEL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001967 kgsl_mem_entry_attach_process(entry, private);
1968 param->gpuaddr = entry->memdesc.gpuaddr;
1969
Jordan Crouse1b897cf2011-10-12 16:57:48 -06001970 kgsl_process_add_stats(private, entry->memtype, param->size);
Jeremy Gebbena5859272012-03-01 12:46:28 -07001971 trace_kgsl_mem_alloc(entry);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001972 } else
1973 kfree(entry);
1974
1975 kgsl_check_idle(dev_priv->device);
1976 return result;
1977}
Jeremy Gebbena7423e42011-04-18 15:11:21 -06001978static long kgsl_ioctl_cff_syncmem(struct kgsl_device_private *dev_priv,
1979 unsigned int cmd, void *data)
1980{
1981 int result = 0;
1982 struct kgsl_cff_syncmem *param = data;
1983 struct kgsl_process_private *private = dev_priv->process_priv;
1984 struct kgsl_mem_entry *entry = NULL;
1985
1986 spin_lock(&private->mem_lock);
1987 entry = kgsl_sharedmem_find_region(private, param->gpuaddr, param->len);
1988 if (entry)
1989 kgsl_cffdump_syncmem(dev_priv, &entry->memdesc, param->gpuaddr,
1990 param->len, true);
1991 else
1992 result = -EINVAL;
1993 spin_unlock(&private->mem_lock);
1994 return result;
1995}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001996
Sushmita Susheelendra41f8fa32011-05-11 17:15:58 -06001997static long kgsl_ioctl_cff_user_event(struct kgsl_device_private *dev_priv,
1998 unsigned int cmd, void *data)
1999{
2000 int result = 0;
2001 struct kgsl_cff_user_event *param = data;
2002
2003 kgsl_cffdump_user_event(param->cff_opcode, param->op1, param->op2,
2004 param->op3, param->op4, param->op5);
2005
2006 return result;
2007}
2008
Jordan Croused4bc9d22011-11-17 13:39:21 -07002009#ifdef CONFIG_GENLOCK
2010struct kgsl_genlock_event_priv {
2011 struct genlock_handle *handle;
2012 struct genlock *lock;
2013};
2014
2015/**
2016 * kgsl_genlock_event_cb - Event callback for a genlock timestamp event
2017 * @device - The KGSL device that expired the timestamp
2018 * @priv - private data for the event
Carter Cooper7e7f02e2012-02-15 09:36:31 -07002019 * @context_id - the context id that goes with the timestamp
Jordan Croused4bc9d22011-11-17 13:39:21 -07002020 * @timestamp - the timestamp that triggered the event
2021 *
2022 * Release a genlock lock following the expiration of a timestamp
2023 */
2024
2025static void kgsl_genlock_event_cb(struct kgsl_device *device,
Carter Cooper7e7f02e2012-02-15 09:36:31 -07002026 void *priv, u32 context_id, u32 timestamp)
Jordan Croused4bc9d22011-11-17 13:39:21 -07002027{
2028 struct kgsl_genlock_event_priv *ev = priv;
2029 int ret;
2030
2031 ret = genlock_lock(ev->handle, GENLOCK_UNLOCK, 0, 0);
2032 if (ret)
2033 KGSL_CORE_ERR("Error while unlocking genlock: %d\n", ret);
2034
2035 genlock_put_handle(ev->handle);
2036
2037 kfree(ev);
2038}
2039
2040/**
2041 * kgsl_add_genlock-event - Create a new genlock event
2042 * @device - KGSL device to create the event on
2043 * @timestamp - Timestamp to trigger the event
2044 * @data - User space buffer containing struct kgsl_genlock_event_priv
2045 * @len - length of the userspace buffer
Jeremy Gebbenfd87f9a2012-02-10 07:06:09 -07002046 * @owner - driver instance that owns this event
Jordan Croused4bc9d22011-11-17 13:39:21 -07002047 * @returns 0 on success or error code on error
2048 *
2049 * Attack to a genlock handle and register an event to release the
2050 * genlock lock when the timestamp expires
2051 */
2052
2053static int kgsl_add_genlock_event(struct kgsl_device *device,
Carter Cooper7e7f02e2012-02-15 09:36:31 -07002054 u32 context_id, u32 timestamp, void __user *data, int len,
Jeremy Gebbenfd87f9a2012-02-10 07:06:09 -07002055 struct kgsl_device_private *owner)
Jordan Croused4bc9d22011-11-17 13:39:21 -07002056{
2057 struct kgsl_genlock_event_priv *event;
2058 struct kgsl_timestamp_event_genlock priv;
2059 int ret;
2060
2061 if (len != sizeof(priv))
2062 return -EINVAL;
2063
2064 if (copy_from_user(&priv, data, sizeof(priv)))
2065 return -EFAULT;
2066
2067 event = kzalloc(sizeof(*event), GFP_KERNEL);
2068
2069 if (event == NULL)
2070 return -ENOMEM;
2071
2072 event->handle = genlock_get_handle_fd(priv.handle);
2073
2074 if (IS_ERR(event->handle)) {
2075 int ret = PTR_ERR(event->handle);
2076 kfree(event);
2077 return ret;
2078 }
2079
Carter Cooper7e7f02e2012-02-15 09:36:31 -07002080 ret = kgsl_add_event(device, context_id, timestamp,
2081 kgsl_genlock_event_cb, event, owner);
Jordan Croused4bc9d22011-11-17 13:39:21 -07002082 if (ret)
2083 kfree(event);
2084
2085 return ret;
2086}
2087#else
2088static long kgsl_add_genlock_event(struct kgsl_device *device,
Carter Cooper7e7f02e2012-02-15 09:36:31 -07002089 u32 context_id, u32 timestamp, void __user *data, int len,
Jeremy Gebbenfd87f9a2012-02-10 07:06:09 -07002090 struct kgsl_device_private *owner)
Jordan Croused4bc9d22011-11-17 13:39:21 -07002091{
2092 return -EINVAL;
2093}
2094#endif
2095
2096/**
2097 * kgsl_ioctl_timestamp_event - Register a new timestamp event from userspace
2098 * @dev_priv - pointer to the private device structure
2099 * @cmd - the ioctl cmd passed from kgsl_ioctl
2100 * @data - the user data buffer from kgsl_ioctl
2101 * @returns 0 on success or error code on failure
2102 */
2103
2104static long kgsl_ioctl_timestamp_event(struct kgsl_device_private *dev_priv,
2105 unsigned int cmd, void *data)
2106{
2107 struct kgsl_timestamp_event *param = data;
2108 int ret;
2109
2110 switch (param->type) {
2111 case KGSL_TIMESTAMP_EVENT_GENLOCK:
2112 ret = kgsl_add_genlock_event(dev_priv->device,
Carter Cooper7e7f02e2012-02-15 09:36:31 -07002113 param->context_id, param->timestamp, param->priv,
2114 param->len, dev_priv);
Jordan Croused4bc9d22011-11-17 13:39:21 -07002115 break;
2116 default:
2117 ret = -EINVAL;
2118 }
2119
2120 return ret;
2121}
2122
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002123typedef long (*kgsl_ioctl_func_t)(struct kgsl_device_private *,
2124 unsigned int, void *);
2125
2126#define KGSL_IOCTL_FUNC(_cmd, _func, _lock) \
2127 [_IOC_NR(_cmd)] = { .cmd = _cmd, .func = _func, .lock = _lock }
2128
2129static const struct {
2130 unsigned int cmd;
2131 kgsl_ioctl_func_t func;
2132 int lock;
2133} kgsl_ioctl_funcs[] = {
2134 KGSL_IOCTL_FUNC(IOCTL_KGSL_DEVICE_GETPROPERTY,
2135 kgsl_ioctl_device_getproperty, 1),
2136 KGSL_IOCTL_FUNC(IOCTL_KGSL_DEVICE_WAITTIMESTAMP,
2137 kgsl_ioctl_device_waittimestamp, 1),
Carter Cooper7e7f02e2012-02-15 09:36:31 -07002138 KGSL_IOCTL_FUNC(IOCTL_KGSL_DEVICE_WAITTIMESTAMP_CTXTID,
2139 kgsl_ioctl_device_waittimestamp_ctxtid, 1),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002140 KGSL_IOCTL_FUNC(IOCTL_KGSL_RINGBUFFER_ISSUEIBCMDS,
2141 kgsl_ioctl_rb_issueibcmds, 1),
2142 KGSL_IOCTL_FUNC(IOCTL_KGSL_CMDSTREAM_READTIMESTAMP,
2143 kgsl_ioctl_cmdstream_readtimestamp, 1),
Carter Cooper7e7f02e2012-02-15 09:36:31 -07002144 KGSL_IOCTL_FUNC(IOCTL_KGSL_CMDSTREAM_READTIMESTAMP_CTXTID,
2145 kgsl_ioctl_cmdstream_readtimestamp_ctxtid, 1),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002146 KGSL_IOCTL_FUNC(IOCTL_KGSL_CMDSTREAM_FREEMEMONTIMESTAMP,
2147 kgsl_ioctl_cmdstream_freememontimestamp, 1),
Carter Cooper7e7f02e2012-02-15 09:36:31 -07002148 KGSL_IOCTL_FUNC(IOCTL_KGSL_CMDSTREAM_FREEMEMONTIMESTAMP_CTXTID,
2149 kgsl_ioctl_cmdstream_freememontimestamp_ctxtid, 1),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002150 KGSL_IOCTL_FUNC(IOCTL_KGSL_DRAWCTXT_CREATE,
2151 kgsl_ioctl_drawctxt_create, 1),
2152 KGSL_IOCTL_FUNC(IOCTL_KGSL_DRAWCTXT_DESTROY,
2153 kgsl_ioctl_drawctxt_destroy, 1),
2154 KGSL_IOCTL_FUNC(IOCTL_KGSL_MAP_USER_MEM,
2155 kgsl_ioctl_map_user_mem, 0),
2156 KGSL_IOCTL_FUNC(IOCTL_KGSL_SHAREDMEM_FROM_PMEM,
2157 kgsl_ioctl_map_user_mem, 0),
2158 KGSL_IOCTL_FUNC(IOCTL_KGSL_SHAREDMEM_FREE,
2159 kgsl_ioctl_sharedmem_free, 0),
2160 KGSL_IOCTL_FUNC(IOCTL_KGSL_SHAREDMEM_FROM_VMALLOC,
2161 kgsl_ioctl_sharedmem_from_vmalloc, 0),
2162 KGSL_IOCTL_FUNC(IOCTL_KGSL_SHAREDMEM_FLUSH_CACHE,
2163 kgsl_ioctl_sharedmem_flush_cache, 0),
2164 KGSL_IOCTL_FUNC(IOCTL_KGSL_GPUMEM_ALLOC,
2165 kgsl_ioctl_gpumem_alloc, 0),
Jeremy Gebbena7423e42011-04-18 15:11:21 -06002166 KGSL_IOCTL_FUNC(IOCTL_KGSL_CFF_SYNCMEM,
2167 kgsl_ioctl_cff_syncmem, 0),
Sushmita Susheelendra41f8fa32011-05-11 17:15:58 -06002168 KGSL_IOCTL_FUNC(IOCTL_KGSL_CFF_USER_EVENT,
2169 kgsl_ioctl_cff_user_event, 0),
Jordan Croused4bc9d22011-11-17 13:39:21 -07002170 KGSL_IOCTL_FUNC(IOCTL_KGSL_TIMESTAMP_EVENT,
Lucille Sylvester9329cf02011-12-02 14:30:41 -07002171 kgsl_ioctl_timestamp_event, 1),
Jordan Crouseed7dd7f2012-03-29 13:16:02 -06002172 KGSL_IOCTL_FUNC(IOCTL_KGSL_SETPROPERTY,
2173 kgsl_ioctl_device_setproperty, 1),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002174};
2175
2176static long kgsl_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
2177{
2178 struct kgsl_device_private *dev_priv = filep->private_data;
Jordan Crouse1e76f612012-08-08 13:24:21 -06002179 unsigned int nr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002180 kgsl_ioctl_func_t func;
2181 int lock, ret;
2182 char ustack[64];
2183 void *uptr = NULL;
2184
2185 BUG_ON(dev_priv == NULL);
2186
2187 /* Workaround for an previously incorrectly defined ioctl code.
2188 This helps ensure binary compatability */
2189
2190 if (cmd == IOCTL_KGSL_CMDSTREAM_FREEMEMONTIMESTAMP_OLD)
2191 cmd = IOCTL_KGSL_CMDSTREAM_FREEMEMONTIMESTAMP;
Jason Varbedian80ba33d2011-07-11 17:29:05 -07002192 else if (cmd == IOCTL_KGSL_CMDSTREAM_READTIMESTAMP_OLD)
2193 cmd = IOCTL_KGSL_CMDSTREAM_READTIMESTAMP;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002194
Jordan Crouse1e76f612012-08-08 13:24:21 -06002195 nr = _IOC_NR(cmd);
2196
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002197 if (cmd & (IOC_IN | IOC_OUT)) {
2198 if (_IOC_SIZE(cmd) < sizeof(ustack))
2199 uptr = ustack;
2200 else {
2201 uptr = kzalloc(_IOC_SIZE(cmd), GFP_KERNEL);
2202 if (uptr == NULL) {
2203 KGSL_MEM_ERR(dev_priv->device,
2204 "kzalloc(%d) failed\n", _IOC_SIZE(cmd));
2205 ret = -ENOMEM;
2206 goto done;
2207 }
2208 }
2209
2210 if (cmd & IOC_IN) {
2211 if (copy_from_user(uptr, (void __user *) arg,
2212 _IOC_SIZE(cmd))) {
2213 ret = -EFAULT;
2214 goto done;
2215 }
2216 } else
2217 memset(uptr, 0, _IOC_SIZE(cmd));
2218 }
2219
2220 if (nr < ARRAY_SIZE(kgsl_ioctl_funcs) &&
Jordan Crouse1e76f612012-08-08 13:24:21 -06002221 kgsl_ioctl_funcs[nr].func != NULL) {
2222
2223 /*
2224 * Make sure that nobody tried to send us a malformed ioctl code
2225 * with a valid NR but bogus flags
2226 */
2227
2228 if (kgsl_ioctl_funcs[nr].cmd != cmd) {
2229 KGSL_DRV_ERR(dev_priv->device,
2230 "Malformed ioctl code %08x\n", cmd);
2231 ret = -ENOIOCTLCMD;
2232 goto done;
2233 }
2234
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002235 func = kgsl_ioctl_funcs[nr].func;
2236 lock = kgsl_ioctl_funcs[nr].lock;
2237 } else {
2238 func = dev_priv->device->ftbl->ioctl;
2239 if (!func) {
2240 KGSL_DRV_INFO(dev_priv->device,
2241 "invalid ioctl code %08x\n", cmd);
Jeremy Gebbenc15b4612012-01-09 09:44:11 -07002242 ret = -ENOIOCTLCMD;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002243 goto done;
2244 }
2245 lock = 1;
2246 }
2247
2248 if (lock) {
2249 mutex_lock(&dev_priv->device->mutex);
2250 kgsl_check_suspended(dev_priv->device);
2251 }
2252
2253 ret = func(dev_priv, cmd, uptr);
2254
2255 if (lock) {
2256 kgsl_check_idle_locked(dev_priv->device);
2257 mutex_unlock(&dev_priv->device->mutex);
2258 }
2259
2260 if (ret == 0 && (cmd & IOC_OUT)) {
2261 if (copy_to_user((void __user *) arg, uptr, _IOC_SIZE(cmd)))
2262 ret = -EFAULT;
2263 }
2264
2265done:
2266 if (_IOC_SIZE(cmd) >= sizeof(ustack))
2267 kfree(uptr);
2268
2269 return ret;
2270}
2271
2272static int
2273kgsl_mmap_memstore(struct kgsl_device *device, struct vm_area_struct *vma)
2274{
2275 struct kgsl_memdesc *memdesc = &device->memstore;
2276 int result;
2277 unsigned int vma_size = vma->vm_end - vma->vm_start;
2278
2279 /* The memstore can only be mapped as read only */
2280
2281 if (vma->vm_flags & VM_WRITE)
2282 return -EPERM;
2283
2284 if (memdesc->size != vma_size) {
2285 KGSL_MEM_ERR(device, "memstore bad size: %d should be %d\n",
2286 vma_size, memdesc->size);
2287 return -EINVAL;
2288 }
2289
2290 vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
2291
Shubhraprakash Das87f68132012-07-30 23:25:13 -07002292 result = remap_pfn_range(vma, vma->vm_start,
2293 device->memstore.physaddr >> PAGE_SHIFT,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002294 vma_size, vma->vm_page_prot);
2295 if (result != 0)
2296 KGSL_MEM_ERR(device, "remap_pfn_range failed: %d\n",
2297 result);
2298
2299 return result;
2300}
2301
Jordan Crouse4283e172011-09-26 14:45:47 -06002302/*
2303 * kgsl_gpumem_vm_open is called whenever a vma region is copied or split.
2304 * Increase the refcount to make sure that the accounting stays correct
2305 */
2306
2307static void kgsl_gpumem_vm_open(struct vm_area_struct *vma)
2308{
2309 struct kgsl_mem_entry *entry = vma->vm_private_data;
2310 kgsl_mem_entry_get(entry);
2311}
2312
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002313static int
2314kgsl_gpumem_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
2315{
2316 struct kgsl_mem_entry *entry = vma->vm_private_data;
2317
Jordan Croused17e9aa2011-10-12 16:57:48 -06002318 if (!entry->memdesc.ops || !entry->memdesc.ops->vmfault)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002319 return VM_FAULT_SIGBUS;
2320
2321 return entry->memdesc.ops->vmfault(&entry->memdesc, vma, vmf);
2322}
2323
2324static void
2325kgsl_gpumem_vm_close(struct vm_area_struct *vma)
2326{
2327 struct kgsl_mem_entry *entry = vma->vm_private_data;
2328 kgsl_mem_entry_put(entry);
2329}
2330
2331static struct vm_operations_struct kgsl_gpumem_vm_ops = {
Jordan Crouse4283e172011-09-26 14:45:47 -06002332 .open = kgsl_gpumem_vm_open,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002333 .fault = kgsl_gpumem_vm_fault,
2334 .close = kgsl_gpumem_vm_close,
2335};
2336
2337static int kgsl_mmap(struct file *file, struct vm_area_struct *vma)
2338{
2339 unsigned long vma_offset = vma->vm_pgoff << PAGE_SHIFT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002340 struct kgsl_device_private *dev_priv = file->private_data;
2341 struct kgsl_process_private *private = dev_priv->process_priv;
Jordan Crousec9559e42012-04-05 16:55:56 -06002342 struct kgsl_mem_entry *entry = NULL;
Jordan Crouse2db0af92011-08-08 16:05:09 -06002343 struct kgsl_device *device = dev_priv->device;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002344
2345 /* Handle leagacy behavior for memstore */
2346
Shubhraprakash Das87f68132012-07-30 23:25:13 -07002347 if (vma_offset == device->memstore.gpuaddr)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002348 return kgsl_mmap_memstore(device, vma);
2349
2350 /* Find a chunk of GPU memory */
2351
2352 spin_lock(&private->mem_lock);
Jordan Crousec9559e42012-04-05 16:55:56 -06002353 entry = kgsl_sharedmem_find(private, vma_offset);
2354
2355 if (entry)
2356 kgsl_mem_entry_get(entry);
2357
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002358 spin_unlock(&private->mem_lock);
2359
2360 if (entry == NULL)
2361 return -EINVAL;
2362
Jordan Croused17e9aa2011-10-12 16:57:48 -06002363 if (!entry->memdesc.ops ||
2364 !entry->memdesc.ops->vmflags ||
2365 !entry->memdesc.ops->vmfault)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002366 return -EINVAL;
2367
2368 vma->vm_flags |= entry->memdesc.ops->vmflags(&entry->memdesc);
2369
2370 vma->vm_private_data = entry;
2371 vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
2372 vma->vm_ops = &kgsl_gpumem_vm_ops;
2373 vma->vm_file = file;
2374
2375 return 0;
2376}
2377
Jordan Crouseb368e9b2012-04-27 14:01:59 -06002378static irqreturn_t kgsl_irq_handler(int irq, void *data)
2379{
2380 struct kgsl_device *device = data;
2381
2382 return device->ftbl->irq_handler(device);
2383
2384}
2385
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002386static const struct file_operations kgsl_fops = {
2387 .owner = THIS_MODULE,
2388 .release = kgsl_release,
2389 .open = kgsl_open,
2390 .mmap = kgsl_mmap,
2391 .unlocked_ioctl = kgsl_ioctl,
2392};
2393
2394struct kgsl_driver kgsl_driver = {
2395 .process_mutex = __MUTEX_INITIALIZER(kgsl_driver.process_mutex),
2396 .ptlock = __SPIN_LOCK_UNLOCKED(kgsl_driver.ptlock),
2397 .devlock = __MUTEX_INITIALIZER(kgsl_driver.devlock),
2398};
2399EXPORT_SYMBOL(kgsl_driver);
2400
Jeremy Gebben4f5f0de2012-03-01 15:51:37 -07002401static void _unregister_device(struct kgsl_device *device)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002402{
2403 int minor;
2404
2405 mutex_lock(&kgsl_driver.devlock);
2406 for (minor = 0; minor < KGSL_DEVICE_MAX; minor++) {
2407 if (device == kgsl_driver.devp[minor])
2408 break;
2409 }
Jeremy Gebben4f5f0de2012-03-01 15:51:37 -07002410 if (minor != KGSL_DEVICE_MAX) {
2411 device_destroy(kgsl_driver.class,
2412 MKDEV(MAJOR(kgsl_driver.major), minor));
2413 kgsl_driver.devp[minor] = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002414 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002415 mutex_unlock(&kgsl_driver.devlock);
2416}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002417
Jeremy Gebben4f5f0de2012-03-01 15:51:37 -07002418static int _register_device(struct kgsl_device *device)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002419{
2420 int minor, ret;
2421 dev_t dev;
2422
2423 /* Find a minor for the device */
2424
2425 mutex_lock(&kgsl_driver.devlock);
2426 for (minor = 0; minor < KGSL_DEVICE_MAX; minor++) {
2427 if (kgsl_driver.devp[minor] == NULL) {
2428 kgsl_driver.devp[minor] = device;
2429 break;
2430 }
2431 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002432 mutex_unlock(&kgsl_driver.devlock);
2433
2434 if (minor == KGSL_DEVICE_MAX) {
2435 KGSL_CORE_ERR("minor devices exhausted\n");
2436 return -ENODEV;
2437 }
2438
2439 /* Create the device */
2440 dev = MKDEV(MAJOR(kgsl_driver.major), minor);
2441 device->dev = device_create(kgsl_driver.class,
2442 device->parentdev,
2443 dev, device,
2444 device->name);
2445
2446 if (IS_ERR(device->dev)) {
Jeremy Gebben4f5f0de2012-03-01 15:51:37 -07002447 mutex_lock(&kgsl_driver.devlock);
2448 kgsl_driver.devp[minor] = NULL;
2449 mutex_unlock(&kgsl_driver.devlock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002450 ret = PTR_ERR(device->dev);
2451 KGSL_CORE_ERR("device_create(%s): %d\n", device->name, ret);
Jeremy Gebben4f5f0de2012-03-01 15:51:37 -07002452 return ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002453 }
2454
2455 dev_set_drvdata(device->parentdev, device);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002456 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002457}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002458
Jordan Crouseb368e9b2012-04-27 14:01:59 -06002459int kgsl_device_platform_probe(struct kgsl_device *device)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002460{
Michael Street8bacdd02012-01-05 14:55:01 -08002461 int result;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002462 int status = -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002463 struct resource *res;
2464 struct platform_device *pdev =
2465 container_of(device->parentdev, struct platform_device, dev);
2466
Jeremy Gebben4f5f0de2012-03-01 15:51:37 -07002467 status = _register_device(device);
2468 if (status)
2469 return status;
2470
2471 /* Initialize logging first, so that failures below actually print. */
2472 kgsl_device_debugfs_init(device);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002473
2474 status = kgsl_pwrctrl_init(device);
2475 if (status)
2476 goto error;
2477
Harsh Vardhan Dwivedif48af7f2012-04-13 12:50:44 -06002478 kgsl_ion_client = msm_ion_client_create(UINT_MAX, KGSL_NAME);
2479
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002480 res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
2481 device->iomemname);
2482 if (res == NULL) {
2483 KGSL_DRV_ERR(device, "platform_get_resource_byname failed\n");
2484 status = -EINVAL;
2485 goto error_pwrctrl_close;
2486 }
2487 if (res->start == 0 || resource_size(res) == 0) {
Jordan Crouse7501d452012-04-19 08:58:44 -06002488 KGSL_DRV_ERR(device, "dev %d invalid register region\n",
2489 device->id);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002490 status = -EINVAL;
2491 goto error_pwrctrl_close;
2492 }
2493
Jordan Crouse7501d452012-04-19 08:58:44 -06002494 device->reg_phys = res->start;
2495 device->reg_len = resource_size(res);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002496
Jeremy Gebben4204d0f2012-03-01 16:06:21 -07002497 if (!devm_request_mem_region(device->dev, device->reg_phys,
2498 device->reg_len, device->name)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002499 KGSL_DRV_ERR(device, "request_mem_region failed\n");
2500 status = -ENODEV;
2501 goto error_pwrctrl_close;
2502 }
2503
Jeremy Gebben4204d0f2012-03-01 16:06:21 -07002504 device->reg_virt = devm_ioremap(device->dev, device->reg_phys,
2505 device->reg_len);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002506
Jordan Crouse7501d452012-04-19 08:58:44 -06002507 if (device->reg_virt == NULL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002508 KGSL_DRV_ERR(device, "ioremap failed\n");
2509 status = -ENODEV;
Jeremy Gebben4204d0f2012-03-01 16:06:21 -07002510 goto error_pwrctrl_close;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002511 }
Jeremy Gebben4f5f0de2012-03-01 15:51:37 -07002512 /*acquire interrupt */
2513 device->pwrctrl.interrupt_num =
2514 platform_get_irq_byname(pdev, device->pwrctrl.irq_name);
2515
2516 if (device->pwrctrl.interrupt_num <= 0) {
2517 KGSL_DRV_ERR(device, "platform_get_irq_byname failed: %d\n",
2518 device->pwrctrl.interrupt_num);
2519 status = -EINVAL;
Jeremy Gebben4204d0f2012-03-01 16:06:21 -07002520 goto error_pwrctrl_close;
Jeremy Gebben4f5f0de2012-03-01 15:51:37 -07002521 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002522
Jeremy Gebben4204d0f2012-03-01 16:06:21 -07002523 status = devm_request_irq(device->dev, device->pwrctrl.interrupt_num,
2524 kgsl_irq_handler, IRQF_TRIGGER_HIGH,
2525 device->name, device);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002526 if (status) {
2527 KGSL_DRV_ERR(device, "request_irq(%d) failed: %d\n",
2528 device->pwrctrl.interrupt_num, status);
Jeremy Gebben4204d0f2012-03-01 16:06:21 -07002529 goto error_pwrctrl_close;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002530 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002531 disable_irq(device->pwrctrl.interrupt_num);
2532
2533 KGSL_DRV_INFO(device,
Jordan Crouse7501d452012-04-19 08:58:44 -06002534 "dev_id %d regs phys 0x%08lx size 0x%08x virt %p\n",
2535 device->id, device->reg_phys, device->reg_len,
2536 device->reg_virt);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002537
Michael Street8bacdd02012-01-05 14:55:01 -08002538 result = kgsl_drm_init(pdev);
2539 if (result)
Jeremy Gebben4204d0f2012-03-01 16:06:21 -07002540 goto error_pwrctrl_close;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002541
Jeremy Gebben4f5f0de2012-03-01 15:51:37 -07002542 kgsl_cffdump_open(device->id);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002543
Jeremy Gebben4f5f0de2012-03-01 15:51:37 -07002544 setup_timer(&device->idle_timer, kgsl_timer, (unsigned long) device);
2545 status = kgsl_create_device_workqueue(device);
2546 if (status)
Jeremy Gebben4204d0f2012-03-01 16:06:21 -07002547 goto error_pwrctrl_close;
Jeremy Gebben4f5f0de2012-03-01 15:51:37 -07002548
2549 status = kgsl_mmu_init(device);
2550 if (status != 0) {
2551 KGSL_DRV_ERR(device, "kgsl_mmu_init failed %d\n", status);
2552 goto error_dest_work_q;
2553 }
2554
2555 status = kgsl_allocate_contiguous(&device->memstore,
Richard Ruigrok2ad5e9d2012-06-14 14:22:05 -07002556 KGSL_MEMSTORE_SIZE);
Jeremy Gebben4f5f0de2012-03-01 15:51:37 -07002557
2558 if (status != 0) {
2559 KGSL_DRV_ERR(device, "kgsl_allocate_contiguous failed %d\n",
2560 status);
2561 goto error_close_mmu;
2562 }
2563
Jeremy Gebben4f5f0de2012-03-01 15:51:37 -07002564 pm_qos_add_request(&device->pm_qos_req_dma, PM_QOS_CPU_DMA_LATENCY,
2565 PM_QOS_DEFAULT_VALUE);
2566
2567 /* Initalize the snapshot engine */
2568 kgsl_device_snapshot_init(device);
2569
2570 /* Initialize common sysfs entries */
2571 kgsl_pwrctrl_init_sysfs(device);
2572
2573 return 0;
2574
2575error_close_mmu:
2576 kgsl_mmu_close(device);
2577error_dest_work_q:
2578 destroy_workqueue(device->work_queue);
2579 device->work_queue = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002580error_pwrctrl_close:
2581 kgsl_pwrctrl_close(device);
2582error:
Jeremy Gebben4f5f0de2012-03-01 15:51:37 -07002583 _unregister_device(device);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002584 return status;
2585}
2586EXPORT_SYMBOL(kgsl_device_platform_probe);
2587
Harsh Vardhan Dwivedi715fb832012-05-18 00:24:18 -06002588int kgsl_postmortem_dump(struct kgsl_device *device, int manual)
2589{
2590 bool saved_nap;
2591 struct kgsl_pwrctrl *pwr = &device->pwrctrl;
2592
2593 BUG_ON(device == NULL);
2594
2595 kgsl_cffdump_hang(device->id);
2596
2597 /* For a manual dump, make sure that the system is idle */
2598
2599 if (manual) {
2600 if (device->active_cnt != 0) {
2601 mutex_unlock(&device->mutex);
2602 wait_for_completion(&device->suspend_gate);
2603 mutex_lock(&device->mutex);
2604 }
2605
2606 if (device->state == KGSL_STATE_ACTIVE)
2607 kgsl_idle(device, KGSL_TIMEOUT_DEFAULT);
2608
2609 }
2610 KGSL_LOG_DUMP(device, "|%s| Dump Started\n", device->name);
2611 KGSL_LOG_DUMP(device, "POWER: FLAGS = %08lX | ACTIVE POWERLEVEL = %08X",
2612 pwr->power_flags, pwr->active_pwrlevel);
2613
2614 KGSL_LOG_DUMP(device, "POWER: INTERVAL TIMEOUT = %08X ",
2615 pwr->interval_timeout);
2616
2617 KGSL_LOG_DUMP(device, "GRP_CLK = %lu ",
2618 kgsl_get_clkrate(pwr->grp_clks[0]));
2619
2620 KGSL_LOG_DUMP(device, "BUS CLK = %lu ",
2621 kgsl_get_clkrate(pwr->ebi1_clk));
2622
2623 /* Disable the idle timer so we don't get interrupted */
2624 del_timer_sync(&device->idle_timer);
2625 mutex_unlock(&device->mutex);
2626 flush_workqueue(device->work_queue);
2627 mutex_lock(&device->mutex);
2628
2629 /* Turn off napping to make sure we have the clocks full
2630 attention through the following process */
2631 saved_nap = device->pwrctrl.nap_allowed;
2632 device->pwrctrl.nap_allowed = false;
2633
2634 /* Force on the clocks */
2635 kgsl_pwrctrl_wake(device);
2636
2637 /* Disable the irq */
2638 kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
2639
2640 /*Call the device specific postmortem dump function*/
2641 device->ftbl->postmortem_dump(device, manual);
2642
2643 /* Restore nap mode */
2644 device->pwrctrl.nap_allowed = saved_nap;
2645
2646 /* On a manual trigger, turn on the interrupts and put
2647 the clocks to sleep. They will recover themselves
2648 on the next event. For a hang, leave things as they
2649 are until recovery kicks in. */
2650
2651 if (manual) {
2652 kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_ON);
2653
2654 /* try to go into a sleep mode until the next event */
2655 kgsl_pwrctrl_request_state(device, KGSL_STATE_SLEEP);
2656 kgsl_pwrctrl_sleep(device);
2657 }
2658
2659 KGSL_LOG_DUMP(device, "|%s| Dump Finished\n", device->name);
2660
2661 return 0;
2662}
2663EXPORT_SYMBOL(kgsl_postmortem_dump);
2664
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002665void kgsl_device_platform_remove(struct kgsl_device *device)
2666{
Jeremy Gebben4f5f0de2012-03-01 15:51:37 -07002667 kgsl_device_snapshot_close(device);
2668
2669 kgsl_cffdump_close(device->id);
2670 kgsl_pwrctrl_uninit_sysfs(device);
2671
Jeremy Gebben4f5f0de2012-03-01 15:51:37 -07002672 pm_qos_remove_request(&device->pm_qos_req_dma);
2673
2674 idr_destroy(&device->context_idr);
2675
2676 kgsl_sharedmem_free(&device->memstore);
2677
2678 kgsl_mmu_close(device);
2679
2680 if (device->work_queue) {
2681 destroy_workqueue(device->work_queue);
2682 device->work_queue = NULL;
2683 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002684 kgsl_pwrctrl_close(device);
2685
Jeremy Gebben4f5f0de2012-03-01 15:51:37 -07002686 _unregister_device(device);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002687}
2688EXPORT_SYMBOL(kgsl_device_platform_remove);
2689
2690static int __devinit
2691kgsl_ptdata_init(void)
2692{
Jordan Crouse6d76c4d2012-03-26 09:50:43 -06002693 kgsl_driver.ptpool = kgsl_mmu_ptpool_init(kgsl_pagetable_count);
2694
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06002695 if (!kgsl_driver.ptpool)
2696 return -ENOMEM;
2697 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002698}
2699
2700static void kgsl_core_exit(void)
2701{
Ranjhith Kalisamy4ad59e92012-05-31 19:15:11 +05302702 kgsl_mmu_ptpool_destroy(kgsl_driver.ptpool);
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06002703 kgsl_driver.ptpool = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002704
Ranjhith Kalisamydad9df52012-06-01 17:05:13 +05302705 kgsl_drm_exit();
2706 kgsl_cffdump_destroy();
2707 kgsl_core_debugfs_close();
Ranjhith Kalisamydad9df52012-06-01 17:05:13 +05302708
Harsh Vardhan Dwivediefa6b012012-06-15 13:02:27 -06002709 /*
2710 * We call kgsl_sharedmem_uninit_sysfs() and device_unregister()
2711 * only if kgsl_driver.virtdev has been populated.
2712 * We check at least one member of kgsl_driver.virtdev to
2713 * see if it is not NULL (and thus, has been populated).
2714 */
2715 if (kgsl_driver.virtdev.class) {
2716 kgsl_sharedmem_uninit_sysfs();
2717 device_unregister(&kgsl_driver.virtdev);
2718 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002719
2720 if (kgsl_driver.class) {
2721 class_destroy(kgsl_driver.class);
2722 kgsl_driver.class = NULL;
2723 }
2724
Ranjhith Kalisamydad9df52012-06-01 17:05:13 +05302725 unregister_chrdev_region(kgsl_driver.major, KGSL_DEVICE_MAX);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002726}
2727
2728static int __init kgsl_core_init(void)
2729{
2730 int result = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002731 /* alloc major and minor device numbers */
2732 result = alloc_chrdev_region(&kgsl_driver.major, 0, KGSL_DEVICE_MAX,
2733 KGSL_NAME);
2734 if (result < 0) {
2735 KGSL_CORE_ERR("alloc_chrdev_region failed err = %d\n", result);
2736 goto err;
2737 }
2738
2739 cdev_init(&kgsl_driver.cdev, &kgsl_fops);
2740 kgsl_driver.cdev.owner = THIS_MODULE;
2741 kgsl_driver.cdev.ops = &kgsl_fops;
2742 result = cdev_add(&kgsl_driver.cdev, MKDEV(MAJOR(kgsl_driver.major), 0),
2743 KGSL_DEVICE_MAX);
2744
2745 if (result) {
2746 KGSL_CORE_ERR("kgsl: cdev_add() failed, dev_num= %d,"
2747 " result= %d\n", kgsl_driver.major, result);
2748 goto err;
2749 }
2750
2751 kgsl_driver.class = class_create(THIS_MODULE, KGSL_NAME);
2752
2753 if (IS_ERR(kgsl_driver.class)) {
2754 result = PTR_ERR(kgsl_driver.class);
2755 KGSL_CORE_ERR("failed to create class %s", KGSL_NAME);
2756 goto err;
2757 }
2758
2759 /* Make a virtual device for managing core related things
2760 in sysfs */
2761 kgsl_driver.virtdev.class = kgsl_driver.class;
2762 dev_set_name(&kgsl_driver.virtdev, "kgsl");
2763 result = device_register(&kgsl_driver.virtdev);
2764 if (result) {
2765 KGSL_CORE_ERR("driver_register failed\n");
2766 goto err;
2767 }
2768
2769 /* Make kobjects in the virtual device for storing statistics */
2770
2771 kgsl_driver.ptkobj =
2772 kobject_create_and_add("pagetables",
2773 &kgsl_driver.virtdev.kobj);
2774
2775 kgsl_driver.prockobj =
2776 kobject_create_and_add("proc",
2777 &kgsl_driver.virtdev.kobj);
2778
2779 kgsl_core_debugfs_init();
2780
2781 kgsl_sharedmem_init_sysfs();
2782 kgsl_cffdump_init();
2783
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002784 INIT_LIST_HEAD(&kgsl_driver.process_list);
2785
Shubhraprakash Das767fdda2011-08-15 15:49:45 -06002786 INIT_LIST_HEAD(&kgsl_driver.pagetable_list);
2787
2788 kgsl_mmu_set_mmutype(ksgl_mmu_type);
2789
2790 if (KGSL_MMU_TYPE_GPU == kgsl_mmu_get_mmutype()) {
2791 result = kgsl_ptdata_init();
2792 if (result)
2793 goto err;
2794 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002795
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002796 return 0;
2797
2798err:
2799 kgsl_core_exit();
2800 return result;
2801}
2802
2803module_init(kgsl_core_init);
2804module_exit(kgsl_core_exit);
2805
2806MODULE_AUTHOR("Qualcomm Innovation Center, Inc.");
2807MODULE_DESCRIPTION("MSM GPU driver");
2808MODULE_LICENSE("GPL");