blob: 09070e4e161126d6ef49a009b6b5278fbc82bfe8 [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/* Copyright (c) 2002,2007-2011, Code Aurora Forum. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 */
13#include <linux/vmalloc.h>
14#include <linux/memory_alloc.h>
15#include <asm/cacheflush.h>
16
17#include "kgsl.h"
18#include "kgsl_sharedmem.h"
19#include "kgsl_cffdump.h"
20#include "kgsl_device.h"
21
22static struct kgsl_process_private *
23_get_priv_from_kobj(struct kobject *kobj)
24{
25 struct kgsl_process_private *private;
26 unsigned long name;
27
28 if (!kobj)
29 return NULL;
30
31 if (sscanf(kobj->name, "%ld", &name) != 1)
32 return NULL;
33
34 list_for_each_entry(private, &kgsl_driver.process_list, list) {
35 if (private->pid == name)
36 return private;
37 }
38
39 return NULL;
40}
41
42/* sharedmem / memory sysfs files */
43
44static ssize_t
45process_show(struct kobject *kobj,
46 struct kobj_attribute *attr,
47 char *buf)
48{
49 struct kgsl_process_private *priv;
50 unsigned int val = 0;
51
52 mutex_lock(&kgsl_driver.process_mutex);
53 priv = _get_priv_from_kobj(kobj);
54
55 if (priv == NULL) {
56 mutex_unlock(&kgsl_driver.process_mutex);
57 return 0;
58 }
59
60 if (!strncmp(attr->attr.name, "user", 4))
61 val = priv->stats.user;
62 if (!strncmp(attr->attr.name, "user_max", 8))
63 val = priv->stats.user_max;
64 if (!strncmp(attr->attr.name, "mapped", 6))
65 val = priv->stats.mapped;
66 if (!strncmp(attr->attr.name, "mapped_max", 10))
67 val = priv->stats.mapped_max;
68 if (!strncmp(attr->attr.name, "flushes", 7))
69 val = priv->stats.flushes;
70
71 mutex_unlock(&kgsl_driver.process_mutex);
72 return snprintf(buf, PAGE_SIZE, "%u\n", val);
73}
74
75#define KGSL_MEMSTAT_ATTR(_name, _show) \
76 static struct kobj_attribute attr_##_name = \
77 __ATTR(_name, 0444, _show, NULL)
78
79KGSL_MEMSTAT_ATTR(user, process_show);
80KGSL_MEMSTAT_ATTR(user_max, process_show);
81KGSL_MEMSTAT_ATTR(mapped, process_show);
82KGSL_MEMSTAT_ATTR(mapped_max, process_show);
83KGSL_MEMSTAT_ATTR(flushes, process_show);
84
85static struct attribute *process_attrs[] = {
86 &attr_user.attr,
87 &attr_user_max.attr,
88 &attr_mapped.attr,
89 &attr_mapped_max.attr,
90 &attr_flushes.attr,
91 NULL
92};
93
94static struct attribute_group process_attr_group = {
95 .attrs = process_attrs,
96};
97
98void
99kgsl_process_uninit_sysfs(struct kgsl_process_private *private)
100{
101 /* Remove the sysfs entry */
102 if (private->kobj) {
103 sysfs_remove_group(private->kobj, &process_attr_group);
104 kobject_put(private->kobj);
105 }
106}
107
108void
109kgsl_process_init_sysfs(struct kgsl_process_private *private)
110{
111 unsigned char name[16];
112
113 /* Add a entry to the sysfs device */
114 snprintf(name, sizeof(name), "%d", private->pid);
115 private->kobj = kobject_create_and_add(name, kgsl_driver.prockobj);
116
117 /* sysfs failure isn't fatal, just annoying */
118 if (private->kobj != NULL) {
119 if (sysfs_create_group(private->kobj, &process_attr_group)) {
120 kobject_put(private->kobj);
121 private->kobj = NULL;
122 }
123 }
124}
125
126static int kgsl_drv_memstat_show(struct device *dev,
127 struct device_attribute *attr,
128 char *buf)
129{
130 unsigned int val = 0;
131
132 if (!strncmp(attr->attr.name, "vmalloc", 7))
133 val = kgsl_driver.stats.vmalloc;
134 else if (!strncmp(attr->attr.name, "vmalloc_max", 11))
135 val = kgsl_driver.stats.vmalloc_max;
136 else if (!strncmp(attr->attr.name, "coherent", 8))
137 val = kgsl_driver.stats.coherent;
138 else if (!strncmp(attr->attr.name, "coherent_max", 12))
139 val = kgsl_driver.stats.coherent_max;
140 else if (!strncmp(attr->attr.name, "mapped", 6))
141 val = kgsl_driver.stats.mapped;
142 else if (!strncmp(attr->attr.name, "mapped_max", 10))
143 val = kgsl_driver.stats.mapped_max;
144
145 return snprintf(buf, PAGE_SIZE, "%u\n", val);
146}
147
148static int kgsl_drv_histogram_show(struct device *dev,
149 struct device_attribute *attr,
150 char *buf)
151{
152 int len = 0;
153 int i;
154
155 for (i = 0; i < 16; i++)
Jeremy Gebbena87bb862011-08-08 16:09:38 -0600156 len += snprintf(buf + len, PAGE_SIZE - len, "%d ",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700157 kgsl_driver.stats.histogram[i]);
158
Jeremy Gebbena87bb862011-08-08 16:09:38 -0600159 len += snprintf(buf + len, PAGE_SIZE - len, "\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700160 return len;
161}
162
163DEVICE_ATTR(vmalloc, 0444, kgsl_drv_memstat_show, NULL);
164DEVICE_ATTR(vmalloc_max, 0444, kgsl_drv_memstat_show, NULL);
165DEVICE_ATTR(coherent, 0444, kgsl_drv_memstat_show, NULL);
166DEVICE_ATTR(coherent_max, 0444, kgsl_drv_memstat_show, NULL);
167DEVICE_ATTR(mapped, 0444, kgsl_drv_memstat_show, NULL);
168DEVICE_ATTR(mapped_max, 0444, kgsl_drv_memstat_show, NULL);
169DEVICE_ATTR(histogram, 0444, kgsl_drv_histogram_show, NULL);
170
171static const struct device_attribute *drv_attr_list[] = {
172 &dev_attr_vmalloc,
173 &dev_attr_vmalloc_max,
174 &dev_attr_coherent,
175 &dev_attr_coherent_max,
176 &dev_attr_mapped,
177 &dev_attr_mapped_max,
178 &dev_attr_histogram,
179 NULL
180};
181
182void
183kgsl_sharedmem_uninit_sysfs(void)
184{
185 kgsl_remove_device_sysfs_files(&kgsl_driver.virtdev, drv_attr_list);
186}
187
188int
189kgsl_sharedmem_init_sysfs(void)
190{
191 return kgsl_create_device_sysfs_files(&kgsl_driver.virtdev,
192 drv_attr_list);
193}
194
195#ifdef CONFIG_OUTER_CACHE
196static void _outer_cache_range_op(int op, unsigned long addr, size_t size)
197{
198 switch (op) {
199 case KGSL_CACHE_OP_FLUSH:
200 outer_flush_range(addr, addr + size);
201 break;
202 case KGSL_CACHE_OP_CLEAN:
203 outer_clean_range(addr, addr + size);
204 break;
205 case KGSL_CACHE_OP_INV:
206 outer_inv_range(addr, addr + size);
207 break;
208 }
209}
210#endif
211
212static unsigned long kgsl_vmalloc_physaddr(struct kgsl_memdesc *memdesc,
213 unsigned int offset)
214{
215 unsigned int addr;
216
217 if (offset > memdesc->size)
218 return 0;
219
220 addr = vmalloc_to_pfn(memdesc->hostptr + offset);
221 return addr << PAGE_SHIFT;
222}
223
224#ifdef CONFIG_OUTER_CACHE
225static void kgsl_vmalloc_outer_cache(struct kgsl_memdesc *memdesc, int op)
226{
227 void *vaddr = memdesc->hostptr;
228 for (; vaddr < (memdesc->hostptr + memdesc->size); vaddr += PAGE_SIZE) {
229 unsigned long paddr = page_to_phys(vmalloc_to_page(vaddr));
230 _outer_cache_range_op(op, paddr, PAGE_SIZE);
231 }
232}
233#endif
234
235static int kgsl_vmalloc_vmfault(struct kgsl_memdesc *memdesc,
236 struct vm_area_struct *vma,
237 struct vm_fault *vmf)
238{
239 unsigned long offset, pg;
240 struct page *page;
241
242 offset = (unsigned long) vmf->virtual_address - vma->vm_start;
243 pg = (unsigned long) memdesc->hostptr + offset;
244
245 page = vmalloc_to_page((void *) pg);
246 if (page == NULL)
247 return VM_FAULT_SIGBUS;
248
249 get_page(page);
250
251 vmf->page = page;
252 return 0;
253}
254
255static int kgsl_vmalloc_vmflags(struct kgsl_memdesc *memdesc)
256{
257 return VM_RESERVED | VM_DONTEXPAND;
258}
259
260static void kgsl_vmalloc_free(struct kgsl_memdesc *memdesc)
261{
262 kgsl_driver.stats.vmalloc -= memdesc->size;
263 vfree(memdesc->hostptr);
264}
265
266static int kgsl_contiguous_vmflags(struct kgsl_memdesc *memdesc)
267{
268 return VM_RESERVED | VM_IO | VM_PFNMAP | VM_DONTEXPAND;
269}
270
271static int kgsl_contiguous_vmfault(struct kgsl_memdesc *memdesc,
272 struct vm_area_struct *vma,
273 struct vm_fault *vmf)
274{
275 unsigned long offset, pfn;
276 int ret;
277
278 offset = ((unsigned long) vmf->virtual_address - vma->vm_start) >>
279 PAGE_SHIFT;
280
281 pfn = (memdesc->physaddr >> PAGE_SHIFT) + offset;
282 ret = vm_insert_pfn(vma, (unsigned long) vmf->virtual_address, pfn);
283
284 if (ret == -ENOMEM || ret == -EAGAIN)
285 return VM_FAULT_OOM;
286 else if (ret == -EFAULT)
287 return VM_FAULT_SIGBUS;
288
289 return VM_FAULT_NOPAGE;
290}
291
292static void kgsl_ebimem_free(struct kgsl_memdesc *memdesc)
293
294{
295 kgsl_driver.stats.coherent -= memdesc->size;
296 if (memdesc->hostptr)
297 iounmap(memdesc->hostptr);
298
299 free_contiguous_memory_by_paddr(memdesc->physaddr);
300}
301
302static void kgsl_coherent_free(struct kgsl_memdesc *memdesc)
303{
304 kgsl_driver.stats.coherent -= memdesc->size;
305 dma_free_coherent(NULL, memdesc->size,
306 memdesc->hostptr, memdesc->physaddr);
307}
308
309static unsigned long kgsl_contiguous_physaddr(struct kgsl_memdesc *memdesc,
310 unsigned int offset)
311{
312 if (offset > memdesc->size)
313 return 0;
314
315 return memdesc->physaddr + offset;
316}
317
318#ifdef CONFIG_OUTER_CACHE
319static void kgsl_contiguous_outer_cache(struct kgsl_memdesc *memdesc, int op)
320{
321 _outer_cache_range_op(op, memdesc->physaddr, memdesc->size);
322}
323#endif
324
325#ifdef CONFIG_OUTER_CACHE
326static void kgsl_userptr_outer_cache(struct kgsl_memdesc *memdesc, int op)
327{
328 void *vaddr = memdesc->hostptr;
329 for (; vaddr < (memdesc->hostptr + memdesc->size); vaddr += PAGE_SIZE) {
330 unsigned long paddr = kgsl_virtaddr_to_physaddr(vaddr);
331 if (paddr)
332 _outer_cache_range_op(op, paddr, PAGE_SIZE);
333 }
334}
335#endif
336
337static unsigned long kgsl_userptr_physaddr(struct kgsl_memdesc *memdesc,
338 unsigned int offset)
339{
340 return kgsl_virtaddr_to_physaddr(memdesc->hostptr + offset);
341}
342
343/* Global - also used by kgsl_drm.c */
344struct kgsl_memdesc_ops kgsl_vmalloc_ops = {
345 .physaddr = kgsl_vmalloc_physaddr,
346 .free = kgsl_vmalloc_free,
347 .vmflags = kgsl_vmalloc_vmflags,
348 .vmfault = kgsl_vmalloc_vmfault,
349#ifdef CONFIG_OUTER_CACHE
350 .outer_cache = kgsl_vmalloc_outer_cache,
351#endif
352};
353EXPORT_SYMBOL(kgsl_vmalloc_ops);
354
355static struct kgsl_memdesc_ops kgsl_ebimem_ops = {
356 .physaddr = kgsl_contiguous_physaddr,
357 .free = kgsl_ebimem_free,
358 .vmflags = kgsl_contiguous_vmflags,
359 .vmfault = kgsl_contiguous_vmfault,
360#ifdef CONFIG_OUTER_CACHE
361 .outer_cache = kgsl_contiguous_outer_cache,
362#endif
363};
364
365static struct kgsl_memdesc_ops kgsl_coherent_ops = {
366 .physaddr = kgsl_contiguous_physaddr,
367 .free = kgsl_coherent_free,
368#ifdef CONFIG_OUTER_CACHE
369 .outer_cache = kgsl_contiguous_outer_cache,
370#endif
371};
372
373/* Global - also used by kgsl.c and kgsl_drm.c */
374struct kgsl_memdesc_ops kgsl_contiguous_ops = {
375 .physaddr = kgsl_contiguous_physaddr,
376#ifdef CONFIG_OUTER_CACHE
377 .outer_cache = kgsl_contiguous_outer_cache
378#endif
379};
380EXPORT_SYMBOL(kgsl_contiguous_ops);
381
382/* Global - also used by kgsl.c */
383struct kgsl_memdesc_ops kgsl_userptr_ops = {
384 .physaddr = kgsl_userptr_physaddr,
385#ifdef CONFIG_OUTER_CACHE
386 .outer_cache = kgsl_userptr_outer_cache,
387#endif
388};
389EXPORT_SYMBOL(kgsl_userptr_ops);
390
391void kgsl_cache_range_op(struct kgsl_memdesc *memdesc, int op)
392{
393 void *addr = memdesc->hostptr;
394 int size = memdesc->size;
395
396 switch (op) {
397 case KGSL_CACHE_OP_FLUSH:
398 dmac_flush_range(addr, addr + size);
399 break;
400 case KGSL_CACHE_OP_CLEAN:
401 dmac_clean_range(addr, addr + size);
402 break;
403 case KGSL_CACHE_OP_INV:
404 dmac_inv_range(addr, addr + size);
405 break;
406 }
407
408 if (memdesc->ops->outer_cache)
409 memdesc->ops->outer_cache(memdesc, op);
410}
411EXPORT_SYMBOL(kgsl_cache_range_op);
412
413static int
414_kgsl_sharedmem_vmalloc(struct kgsl_memdesc *memdesc,
415 struct kgsl_pagetable *pagetable,
416 void *ptr, size_t size, unsigned int protflags)
417{
418 int result;
419
420 memdesc->size = size;
421 memdesc->pagetable = pagetable;
422 memdesc->priv = KGSL_MEMFLAGS_CACHED;
423 memdesc->ops = &kgsl_vmalloc_ops;
424 memdesc->hostptr = (void *) ptr;
425
426 kgsl_cache_range_op(memdesc, KGSL_CACHE_OP_INV);
427
428 result = kgsl_mmu_map(pagetable, memdesc, protflags);
429
430 if (result) {
431 kgsl_sharedmem_free(memdesc);
432 } else {
433 int order;
434
435 KGSL_STATS_ADD(size, kgsl_driver.stats.vmalloc,
436 kgsl_driver.stats.vmalloc_max);
437
438 order = get_order(size);
439
440 if (order < 16)
441 kgsl_driver.stats.histogram[order]++;
442 }
443
444 return result;
445}
446
447int
448kgsl_sharedmem_vmalloc(struct kgsl_memdesc *memdesc,
449 struct kgsl_pagetable *pagetable, size_t size)
450{
451 void *ptr;
452
453 BUG_ON(size == 0);
454
455 size = ALIGN(size, PAGE_SIZE * 2);
456 ptr = vmalloc(size);
457
458 if (ptr == NULL) {
459 KGSL_CORE_ERR("vmalloc(%d) failed\n", size);
460 return -ENOMEM;
461 }
462
463 return _kgsl_sharedmem_vmalloc(memdesc, pagetable, ptr, size,
464 GSL_PT_PAGE_RV | GSL_PT_PAGE_WV);
465}
466EXPORT_SYMBOL(kgsl_sharedmem_vmalloc);
467
468int
469kgsl_sharedmem_vmalloc_user(struct kgsl_memdesc *memdesc,
470 struct kgsl_pagetable *pagetable,
471 size_t size, int flags)
472{
473 void *ptr;
474 unsigned int protflags;
475
476 BUG_ON(size == 0);
477 ptr = vmalloc_user(size);
478
479 if (ptr == NULL) {
480 KGSL_CORE_ERR("vmalloc_user(%d) failed: allocated=%d\n",
481 size, kgsl_driver.stats.vmalloc);
482 return -ENOMEM;
483 }
484
485 protflags = GSL_PT_PAGE_RV;
486 if (!(flags & KGSL_MEMFLAGS_GPUREADONLY))
487 protflags |= GSL_PT_PAGE_WV;
488
489 return _kgsl_sharedmem_vmalloc(memdesc, pagetable, ptr, size,
490 protflags);
491}
492EXPORT_SYMBOL(kgsl_sharedmem_vmalloc_user);
493
494int
495kgsl_sharedmem_alloc_coherent(struct kgsl_memdesc *memdesc, size_t size)
496{
497 size = ALIGN(size, PAGE_SIZE);
498
499 memdesc->hostptr = dma_alloc_coherent(NULL, size, &memdesc->physaddr,
500 GFP_KERNEL);
501 if (memdesc->hostptr == NULL) {
502 KGSL_CORE_ERR("dma_alloc_coherent(%d) failed\n", size);
503 return -ENOMEM;
504 }
505
506 memdesc->size = size;
507 memdesc->ops = &kgsl_coherent_ops;
508
509 /* Record statistics */
510
511 KGSL_STATS_ADD(size, kgsl_driver.stats.coherent,
512 kgsl_driver.stats.coherent_max);
513
514 return 0;
515}
516EXPORT_SYMBOL(kgsl_sharedmem_alloc_coherent);
517
518void kgsl_sharedmem_free(struct kgsl_memdesc *memdesc)
519{
520 if (memdesc == NULL || memdesc->size == 0)
521 return;
522
523 if (memdesc->gpuaddr)
524 kgsl_mmu_unmap(memdesc->pagetable, memdesc);
525
526 if (memdesc->ops->free)
527 memdesc->ops->free(memdesc);
528
529 memset(memdesc, 0, sizeof(*memdesc));
530}
531EXPORT_SYMBOL(kgsl_sharedmem_free);
532
533static int
534_kgsl_sharedmem_ebimem(struct kgsl_memdesc *memdesc,
535 struct kgsl_pagetable *pagetable, size_t size)
536{
537 int result;
538
539 memdesc->physaddr = allocate_contiguous_ebi_nomap(size, SZ_8K);
540
541 if (memdesc->physaddr == 0) {
542 KGSL_CORE_ERR("allocate_contiguous_ebi_nomap(%d) failed\n",
543 size);
544 return -ENOMEM;
545 }
546
547 memdesc->size = size;
548 memdesc->pagetable = pagetable;
549 memdesc->ops = &kgsl_ebimem_ops;
550
551 result = kgsl_mmu_map(pagetable, memdesc,
552 GSL_PT_PAGE_RV | GSL_PT_PAGE_WV);
553
554 if (result)
555 kgsl_sharedmem_free(memdesc);
556
557 KGSL_STATS_ADD(size, kgsl_driver.stats.coherent,
558 kgsl_driver.stats.coherent_max);
559
560 return result;
561}
562
563int
564kgsl_sharedmem_ebimem_user(struct kgsl_memdesc *memdesc,
565 struct kgsl_pagetable *pagetable,
566 size_t size, int flags)
567{
568 size = ALIGN(size, PAGE_SIZE);
569 return _kgsl_sharedmem_ebimem(memdesc, pagetable, size);
570}
571EXPORT_SYMBOL(kgsl_sharedmem_ebimem_user);
572
573int
574kgsl_sharedmem_ebimem(struct kgsl_memdesc *memdesc,
575 struct kgsl_pagetable *pagetable, size_t size)
576{
577 int result;
578 size = ALIGN(size, 8192);
579 result = _kgsl_sharedmem_ebimem(memdesc, pagetable, size);
580
581 if (result)
582 return result;
583
584 memdesc->hostptr = ioremap(memdesc->physaddr, size);
585
586 if (memdesc->hostptr == NULL) {
587 KGSL_CORE_ERR("ioremap failed\n");
588 kgsl_sharedmem_free(memdesc);
589 return -ENOMEM;
590 }
591
592 return 0;
593}
594EXPORT_SYMBOL(kgsl_sharedmem_ebimem);
595
596int
597kgsl_sharedmem_readl(const struct kgsl_memdesc *memdesc,
598 uint32_t *dst,
599 unsigned int offsetbytes)
600{
601 BUG_ON(memdesc == NULL || memdesc->hostptr == NULL || dst == NULL);
602 WARN_ON(offsetbytes + sizeof(unsigned int) > memdesc->size);
603
604 if (offsetbytes + sizeof(unsigned int) > memdesc->size)
605 return -ERANGE;
606
607 *dst = readl_relaxed(memdesc->hostptr + offsetbytes);
608 return 0;
609}
610EXPORT_SYMBOL(kgsl_sharedmem_readl);
611
612int
613kgsl_sharedmem_writel(const struct kgsl_memdesc *memdesc,
614 unsigned int offsetbytes,
615 uint32_t src)
616{
617 BUG_ON(memdesc == NULL || memdesc->hostptr == NULL);
618 BUG_ON(offsetbytes + sizeof(unsigned int) > memdesc->size);
619
620 kgsl_cffdump_setmem(memdesc->physaddr + offsetbytes,
621 src, sizeof(uint));
622 writel_relaxed(src, memdesc->hostptr + offsetbytes);
623 return 0;
624}
625EXPORT_SYMBOL(kgsl_sharedmem_writel);
626
627int
628kgsl_sharedmem_set(const struct kgsl_memdesc *memdesc, unsigned int offsetbytes,
629 unsigned int value, unsigned int sizebytes)
630{
631 BUG_ON(memdesc == NULL || memdesc->hostptr == NULL);
632 BUG_ON(offsetbytes + sizebytes > memdesc->size);
633
634 kgsl_cffdump_setmem(memdesc->physaddr + offsetbytes, value,
635 sizebytes);
636 memset(memdesc->hostptr + offsetbytes, value, sizebytes);
637 return 0;
638}
639EXPORT_SYMBOL(kgsl_sharedmem_set);