Initial commit
[kernel/linux-3.0.git] / drivers / gpu / vithar_rev0 / kbase / src / linux / mali_kbase_mem_linux.c
1 /*
2  *
3  * (C) COPYRIGHT 2010-2011 ARM Limited. All rights reserved.
4  *
5  * This program is free software and is provided to you under the terms of the GNU General Public License version 2
6  * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
7  * 
8  * A copy of the licence is included with the program, and can also be obtained from Free Software
9  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
10  * 
11  */
12
13
14
15 /**
16  * @file mali_kbase_mem_linux.c
17  * Base kernel memory APIs, Linux implementation.
18  */
19
20 /* #define DEBUG        1 */
21
22 #include <linux/kernel.h>
23 #include <linux/bug.h>
24 #include <linux/mm.h>
25 #include <linux/fs.h>
26 #include <linux/dma-mapping.h>
27
28 #include <kbase/src/common/mali_kbase.h>
29 #include <kbase/src/linux/mali_kbase_mem_linux.h>
30
31 struct kbase_va_region *kbase_pmem_alloc(struct kbase_context *kctx, u32 size,
32                                          u32 flags, u16 *pmem_cookie)
33 {
34         struct kbase_va_region *reg;
35         u16 cookie;
36
37         OSK_ASSERT(kctx != NULL);
38         OSK_ASSERT(pmem_cookie != NULL);
39
40         if ( 0 == size )
41         {
42                 goto out1;
43         }
44
45         if (!kbase_check_alloc_flags(flags))
46         {
47                 goto out1;
48         }
49
50         reg = kbase_alloc_free_region(kctx, 0, size, KBASE_REG_ZONE_PMEM);
51         if (!reg)
52                 goto out1;
53
54         reg->flags &= ~KBASE_REG_FREE;
55
56         kbase_update_region_flags(reg, flags, MALI_FALSE);
57
58         if (kbase_alloc_phy_pages(reg, size, size))
59                 goto out2;
60
61         reg->nr_alloc_pages = size;
62         reg->extent = 0;
63
64         kbase_gpu_vm_lock(kctx);
65         if (!kctx->osctx.cookies)
66                 goto out3;
67         
68         cookie = __ffs(kctx->osctx.cookies);
69         kctx->osctx.cookies &= ~(1UL << cookie);
70         reg->flags &= ~KBASE_REG_COOKIE_MASK;
71         reg->flags |= KBASE_REG_COOKIE(cookie);
72         
73         OSK_DLIST_PUSH_FRONT(&kctx->osctx.reg_pending, reg,
74                                 struct kbase_va_region, link);
75
76         *pmem_cookie = cookie;
77         kbase_gpu_vm_unlock(kctx);
78
79         return reg;
80
81 out3:
82         kbase_gpu_vm_unlock(kctx);
83         kbase_free_phy_pages(reg);
84 out2:
85         osk_free(reg);
86 out1:
87         return NULL;
88         
89 }
90 KBASE_EXPORT_TEST_API(kbase_pmem_alloc)
91
92 /*
93  * Callback for munmap(). PMEM receives a special treatment, as it
94  * frees the memory at the same time it gets unmapped. This avoids the
95  * map/unmap race where map reuses a memory range that has been
96  * unmapped from CPU, but still mapped on GPU.
97  */
98 STATIC void kbase_cpu_vm_close(struct vm_area_struct *vma)
99 {
100         struct kbase_va_region *reg = vma->vm_private_data;
101         kbase_context *kctx = reg->kctx;
102         mali_error err;
103
104         kbase_gpu_vm_lock(kctx);
105
106         err = kbase_cpu_free_mapping(reg, vma);
107         if (!err &&
108             (reg->flags & KBASE_REG_ZONE_MASK) == KBASE_REG_ZONE_PMEM)
109         {
110                 kbase_mem_free_region(kctx, reg);
111         }
112
113         kbase_gpu_vm_unlock(kctx);
114 }
115 KBASE_EXPORT_TEST_API(kbase_cpu_vm_close)
116
117 static const struct vm_operations_struct kbase_vm_ops = {
118         .close = kbase_cpu_vm_close,
119 };
120
121 static int kbase_cpu_mmap(struct kbase_va_region *reg, struct vm_area_struct *vma, void *kaddr, u32 nr_pages)
122 {
123         struct kbase_cpu_mapping *map;
124         u64 start_off = vma->vm_pgoff - reg->start_pfn;
125         osk_phy_addr *page_array;
126         int err = 0;
127         int i;
128
129         map = osk_calloc(sizeof(*map));
130         if (!map)
131         {
132                 WARN_ON(1);
133                 err = -ENOMEM;
134                 goto out;
135         }
136
137         /*
138          * VM_DONTCOPY - don't make this mapping available in fork'ed processes
139          * VM_DONTEXPAND - disable mremap on this region
140          * VM_RESERVED & VM_IO - disables paging
141          * VM_MIXEDMAP - Support mixing struct page*s and raw pfns.
142          *               This is needed to support using the dedicated and
143          *               the OS based memory backends together.
144          */
145         /*
146          * This will need updating to propagate coherency flags
147          * See MIDBASE-1057
148          */
149         vma->vm_flags |= VM_DONTCOPY | VM_DONTEXPAND | VM_RESERVED | VM_IO | VM_MIXEDMAP;
150         vma->vm_ops = &kbase_vm_ops;
151         vma->vm_private_data = reg;
152
153         page_array = kbase_get_phy_pages(reg);
154
155         if (!(reg->flags & KBASE_REG_CPU_CACHED))
156         {
157                 /* We can't map vmalloc'd memory uncached.
158                  * Other memory will have been returned from
159                  * osk_phy_pages_alloc which should have done the cache
160                  * maintenance necessary to support an uncached mapping
161                  */
162                 BUG_ON(kaddr);
163                 vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
164         }
165
166         if (!kaddr)
167         {
168                 for (i = 0; i < nr_pages; i++)
169                 {
170                         err = vm_insert_mixed(vma, vma->vm_start + (i << OSK_PAGE_SHIFT), page_array[i + start_off] >> OSK_PAGE_SHIFT);
171                         WARN_ON(err);
172                         if (err)
173                                 break;
174                 }
175         }
176         else
177         {
178                 /* vmalloc remaping is easy... */
179                 err = remap_vmalloc_range(vma, kaddr, 0);
180                 WARN_ON(err);
181         }
182
183         if (err)
184         {
185                 osk_free(map);
186                 goto out;
187         }
188
189         map->uaddr = (osk_virt_addr)vma->vm_start;
190         map->nr_pages = nr_pages;
191         map->page_off = start_off;
192         map->private = vma;
193
194         OSK_DLIST_PUSH_FRONT(&reg->map_list, map,
195                                 struct kbase_cpu_mapping, link);
196
197 out:
198         return err;
199 }
200
201 static int kbase_rb_mmap(struct kbase_context *kctx,
202                          struct vm_area_struct *vma,
203                          struct kbase_va_region **reg,
204                          void **kmap_addr)
205 {
206         struct kbase_va_region *new_reg;
207         void *kaddr;
208         u32 nr_pages;
209         size_t size;
210         int err = 0;
211         mali_error m_err =  MALI_ERROR_NONE;
212
213         pr_debug("in kbase_rb_mmap\n");
214         size = (vma->vm_end - vma->vm_start);
215         nr_pages = size  >> OSK_PAGE_SHIFT;
216
217         if (kctx->jctx.pool_size < size)
218         {
219                 err = -EINVAL;
220                 goto out;
221         }
222
223         kaddr = kctx->jctx.pool;
224
225         new_reg = kbase_alloc_free_region(kctx, 0, nr_pages, KBASE_REG_ZONE_PMEM);
226         if (!new_reg)
227         {
228                 err = -ENOMEM;
229                 WARN_ON(1);
230                 goto out;
231         }
232
233         new_reg->flags  &= ~KBASE_REG_FREE;
234         new_reg->flags  |= KBASE_REG_IS_RB | KBASE_REG_CPU_CACHED;
235
236         m_err = kbase_add_va_region(kctx, new_reg, vma->vm_start, nr_pages, 1);
237         if (MALI_ERROR_NONE != m_err)
238         {
239                 pr_debug("kbase_rb_mmap: kbase_add_va_region failed\n");
240                 /* Free allocated new_reg */
241                 kbase_free_alloced_region(new_reg);
242                 err = -ENOMEM;
243                 goto out;
244         }
245
246         *kmap_addr      = kaddr;
247         *reg            = new_reg;
248
249         pr_debug("kbase_rb_mmap done\n");
250         return 0;
251
252 out:
253         return err;
254 }
255
256 static int  kbase_trace_buffer_mmap(struct kbase_context * kctx, struct vm_area_struct * vma, struct kbase_va_region **reg, void **kaddr)
257 {
258         struct kbase_va_region *new_reg;
259         u32 nr_pages;
260         size_t size;
261         int err = 0;
262         u32 * tb;
263
264         pr_debug("in %s\n", __func__);
265         size = (vma->vm_end - vma->vm_start);
266         nr_pages = size  >> OSK_PAGE_SHIFT;
267
268         if (!kctx->jctx.tb)
269         {
270                 tb = osk_vmalloc(size);
271                 if (NULL == tb)
272                 {
273                         err = -ENOMEM;
274                         goto out;
275                 }
276
277                 kbase_device_trace_buffer_install(kctx, tb, size);
278         }
279         else
280         {
281                 err = -EINVAL;
282                 goto out;
283         }
284
285         *kaddr = kctx->jctx.tb;
286
287         new_reg = kbase_alloc_free_region(kctx, 0, nr_pages, KBASE_REG_ZONE_PMEM);
288         if (!new_reg)
289         {
290                 err = -ENOMEM;
291                 WARN_ON(1);
292                 goto disconnect;
293         }
294
295         new_reg->flags  &= ~KBASE_REG_FREE;
296         new_reg->flags  |= KBASE_REG_IS_TB | KBASE_REG_CPU_CACHED;
297
298         if (kbase_add_va_region(kctx, new_reg, vma->vm_start, nr_pages, 1))
299                 BUG_ON(1);
300
301         *reg            = new_reg;
302
303         /* map read only, noexec */
304         vma->vm_flags &= ~(VM_WRITE|VM_EXEC);
305         /* the rest of the flags is added by the cpu_mmap handler */
306
307         pr_debug("%s done\n", __func__);
308         return 0;
309
310 disconnect:
311         kbase_device_trace_buffer_uninstall(kctx);
312         osk_vfree(tb);
313 out:
314         return err;
315
316 }
317
318 static int kbase_mmu_dump_mmap( struct kbase_context *kctx,
319                                 struct vm_area_struct *vma,
320                                 struct kbase_va_region **reg,
321                                 void **kmap_addr )
322 {
323         struct kbase_va_region *new_reg;
324         void *kaddr;
325         u32 nr_pages;
326         size_t size;
327         int err = 0;
328
329         pr_debug("in kbase_mmu_dump_mmap\n");
330         size = (vma->vm_end - vma->vm_start);
331         nr_pages = size  >> OSK_PAGE_SHIFT;
332
333         kaddr = kbase_mmu_dump(kctx, nr_pages);
334         
335         if (!kaddr)
336         {
337                 err = -ENOMEM;
338                 goto out;
339         }
340
341         new_reg = kbase_alloc_free_region(kctx, 0, nr_pages, KBASE_REG_ZONE_PMEM);
342         if (!new_reg)
343         {
344                 err = -ENOMEM;
345                 WARN_ON(1);
346                 goto out;
347         }
348
349         new_reg->flags &= ~KBASE_REG_FREE;
350         new_reg->flags |= KBASE_REG_IS_MMU_DUMP | KBASE_REG_CPU_CACHED;
351
352         if (kbase_add_va_region(kctx, new_reg, vma->vm_start, nr_pages, 1))
353                 BUG_ON(1);
354
355         *kmap_addr  = kaddr;
356         *reg        = new_reg;
357
358         pr_debug("kbase_mmu_dump_mmap done\n");
359         return 0;
360
361 out:
362         return err;
363 }
364
365 /* must be called with the gpu vm lock held */
366
367 struct kbase_va_region * kbase_lookup_cookie(struct kbase_context * kctx, mali_addr64 cookie)
368 {
369         struct kbase_va_region * reg;
370         mali_addr64 test_cookie;
371
372         OSK_ASSERT(kctx != NULL);
373
374         test_cookie = KBASE_REG_COOKIE(cookie);
375
376         OSK_DLIST_FOREACH(&kctx->osctx.reg_pending, struct kbase_va_region, link, reg)
377         {
378                 if ((reg->flags & KBASE_REG_COOKIE_MASK) == test_cookie)
379                 {
380                         return reg;
381                 }
382         }
383
384         return NULL; /* not found */
385 }
386 KBASE_EXPORT_TEST_API(kbase_lookup_cookie)
387
388 void kbase_unlink_cookie(struct kbase_context * kctx, mali_addr64 cookie, struct kbase_va_region * reg)
389 {
390         OSKP_ASSERT(kctx != NULL);
391         OSKP_ASSERT(reg != NULL);
392         OSKP_ASSERT(MALI_TRUE == OSK_DLIST_MEMBER_OF(&kctx->osctx.reg_pending, reg, link));
393         OSKP_ASSERT(KBASE_REG_COOKIE(cookie) == (reg->flags & KBASE_REG_COOKIE_MASK));
394         OSKP_ASSERT((kctx->osctx.cookies & (1UL << cookie)) == 0);
395
396         OSK_DLIST_REMOVE(&kctx->osctx.reg_pending, reg, link);
397         kctx->osctx.cookies |= (1UL << cookie); /* mark as resolved */
398 }
399
400 KBASE_EXPORT_TEST_API(kbase_unlink_cookie)
401
402 void kbase_os_mem_map_lock(struct kbase_context * kctx)
403 {
404         struct mm_struct * mm = current->mm;
405         (void)kctx;
406         down_read(&mm->mmap_sem);
407 }
408
409 void kbase_os_mem_map_unlock(struct kbase_context * kctx)
410 {
411         struct mm_struct * mm = current->mm;
412         (void)kctx;
413         up_read(&mm->mmap_sem);
414 }
415
416 int kbase_mmap(struct file *file, struct vm_area_struct *vma)
417 {
418         struct kbase_context *kctx = file->private_data;
419         struct kbase_va_region *reg;
420         void *kaddr = NULL;
421         u32 nr_pages;
422         int err = 0;
423
424         pr_debug("kbase_mmap\n");
425         nr_pages = (vma->vm_end - vma->vm_start) >> OSK_PAGE_SHIFT;
426         
427         if ( 0 == nr_pages )
428         {
429                 err = -EINVAL;
430                 goto out;
431         }
432
433         kbase_gpu_vm_lock(kctx);
434
435         if (vma->vm_pgoff == KBASE_REG_COOKIE_RB)
436         {
437                 /* Reserve offset 0 for the shared ring-buffer */
438                 if ((err = kbase_rb_mmap(kctx, vma, &reg, &kaddr)))
439                         goto out_unlock;
440
441                 pr_debug("kbase_rb_mmap ok\n");
442                 goto map;
443         }
444         else if (vma->vm_pgoff == KBASE_REG_COOKIE_TB)
445         {
446                 err = kbase_trace_buffer_mmap(kctx, vma, &reg, &kaddr);
447                 if (0 != err)
448                         goto out_unlock;
449                 pr_debug("kbase_trace_buffer_mmap ok\n");
450                 goto map;
451         }
452         else if (vma->vm_pgoff == KBASE_REG_COOKIE_MMU_DUMP)
453         {
454                 /* MMU dump */
455                 if ((err = kbase_mmu_dump_mmap(kctx, vma, &reg, &kaddr)))
456                         goto out_unlock;
457
458                 goto map;
459         }
460
461         if (vma->vm_pgoff < OSK_PAGE_SIZE) /* first page is reserved for cookie resolution */
462         {
463                 /* PMEM stuff, fetch the right region */
464                 reg = kbase_lookup_cookie(kctx, vma->vm_pgoff);
465
466                 if (NULL != reg)
467                 {
468                         if (reg->nr_pages != nr_pages)
469                         {
470                                 /* incorrect mmap size */
471                                 /* leave the cookie for a potential later mapping, or to be reclaimed later when the context is freed */
472                                 err = -ENOMEM;
473                                 goto out_unlock;
474                         }
475
476                         kbase_unlink_cookie(kctx, vma->vm_pgoff, reg);
477
478                         /*
479                          * If we cannot map it in GPU space,
480                          * then something is *very* wrong. We
481                          * might as well die now.
482                          */
483                         if (kbase_gpu_mmap(kctx, reg, vma->vm_start,
484                                            nr_pages, 1))
485                                 BUG_ON(1);
486
487                         /*
488                          * Overwrite the offset with the
489                          * region start_pfn, so we effectively
490                          * map from offset 0 in the region.
491                          */
492                         vma->vm_pgoff = reg->start_pfn;
493                         goto map;
494                 }
495
496                 err = -ENOMEM;
497                 goto out_unlock;
498         }
499         else if (vma->vm_pgoff < KBASE_REG_ZONE_TMEM_BASE)
500         {
501                 /* invalid offset as it identifies an already mapped pmem */
502                 err = -ENOMEM;
503                 goto out_unlock;
504         }
505         else
506         {
507                 /* TMEM case */
508                 OSK_DLIST_FOREACH(&kctx->reg_list,
509                                      struct kbase_va_region, link, reg)
510                 {
511                         if (reg->start_pfn <= vma->vm_pgoff &&
512                             (reg->start_pfn + reg->nr_alloc_pages) >= (vma->vm_pgoff + nr_pages) &&
513                             (reg->flags & (KBASE_REG_ZONE_MASK | KBASE_REG_FREE)) == KBASE_REG_ZONE_TMEM)
514                         {
515                                 /* Match! */
516                                 goto map;
517                         }
518                             
519                 }
520
521                 err = -ENOMEM;
522                 goto out_unlock;
523         }
524 map:
525         err = kbase_cpu_mmap(reg, vma, kaddr, nr_pages);
526         
527         if (vma->vm_pgoff == KBASE_REG_COOKIE_MMU_DUMP) {
528                 /* MMU dump - userspace should now have a reference on
529                  * the pages, so we can now free the kernel mapping */
530                 osk_vfree(kaddr);
531         }
532 out_unlock:
533         kbase_gpu_vm_unlock(kctx);
534 out:
535         if (err)
536         {
537                 pr_err("mmap failed %d\n", err);
538         }
539         return err;
540 }
541 KBASE_EXPORT_TEST_API(kbase_mmap)
542
543 mali_error kbase_create_os_context(kbase_os_context *osctx)
544 {
545         OSK_ASSERT(osctx != NULL);
546
547         OSK_DLIST_INIT(&osctx->reg_pending);
548         osctx->cookies = ~KBASE_REG_RESERVED_COOKIES;
549         init_waitqueue_head(&osctx->event_queue);
550
551         return MALI_ERROR_NONE;
552 }
553 KBASE_EXPORT_TEST_API(kbase_create_os_context)
554
555 static void kbase_reg_pending_dtor(struct kbase_va_region *reg)
556 {
557         kbase_free_phy_pages(reg);
558         pr_info("Freeing pending unmapped region\n");
559         osk_free(reg);
560 }
561
562 void kbase_destroy_os_context(kbase_os_context *osctx)
563 {
564         OSK_ASSERT(osctx != NULL);
565
566         OSK_DLIST_EMPTY_LIST(&osctx->reg_pending, struct kbase_va_region,
567                                 link, kbase_reg_pending_dtor);
568 }
569 KBASE_EXPORT_TEST_API(kbase_destroy_os_context)