video: tegra: nvmap: Remove high mem page cache flush.
[linux-2.6.git] / drivers / video / tegra / nvmap / nvmap_handle.c
1 /*
2  * drivers/video/tegra/nvmap/nvmap_handle.c
3  *
4  * Handle allocation and freeing routines for nvmap
5  *
6  * Copyright (c) 2009-2011, NVIDIA Corporation.
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful, but WITHOUT
14  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
16  * more details.
17  *
18  * You should have received a copy of the GNU General Public License along
19  * with this program; if not, write to the Free Software Foundation, Inc.,
20  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21  */
22
23 #include <linux/err.h>
24 #include <linux/kernel.h>
25 #include <linux/list.h>
26 #include <linux/mm.h>
27 #include <linux/rbtree.h>
28 #include <linux/slab.h>
29 #include <linux/vmalloc.h>
30 #include <linux/fs.h>
31
32 #include <asm/cacheflush.h>
33 #include <asm/outercache.h>
34 #include <asm/pgtable.h>
35
36 #include <mach/iovmm.h>
37 #include <mach/nvmap.h>
38
39 #include <linux/vmstat.h>
40 #include <linux/swap.h>
41
42 #include "nvmap.h"
43 #include "nvmap_mru.h"
44 #include "nvmap_common.h"
45
46 #define PRINT_CARVEOUT_CONVERSION 0
47 #if PRINT_CARVEOUT_CONVERSION
48 #define PR_INFO pr_info
49 #else
50 #define PR_INFO(...)
51 #endif
52
53 #define NVMAP_SECURE_HEAPS      (NVMAP_HEAP_CARVEOUT_IRAM | NVMAP_HEAP_IOVMM | \
54                                  NVMAP_HEAP_CARVEOUT_VPR)
55 #ifdef CONFIG_NVMAP_HIGHMEM_ONLY
56 #define GFP_NVMAP               (__GFP_HIGHMEM | __GFP_NOWARN)
57 #else
58 #define GFP_NVMAP               (GFP_KERNEL | __GFP_HIGHMEM | __GFP_NOWARN)
59 #endif
60 /* handles may be arbitrarily large (16+MiB), and any handle allocated from
61  * the kernel (i.e., not a carveout handle) includes its array of pages. to
62  * preserve kmalloc space, if the array of pages exceeds PAGELIST_VMALLOC_MIN,
63  * the array is allocated using vmalloc. */
64 #define PAGELIST_VMALLOC_MIN    (PAGE_SIZE * 2)
65
66 static inline void *altalloc(size_t len)
67 {
68         if (len >= PAGELIST_VMALLOC_MIN)
69                 return vmalloc(len);
70         else
71                 return kmalloc(len, GFP_KERNEL);
72 }
73
74 static inline void altfree(void *ptr, size_t len)
75 {
76         if (!ptr)
77                 return;
78
79         if (len >= PAGELIST_VMALLOC_MIN)
80                 vfree(ptr);
81         else
82                 kfree(ptr);
83 }
84
85 void _nvmap_handle_free(struct nvmap_handle *h)
86 {
87         struct nvmap_device *dev = h->dev;
88         unsigned int i, nr_page;
89
90         if (nvmap_handle_remove(dev, h) != 0)
91                 return;
92
93         if (!h->alloc)
94                 goto out;
95
96         if (!h->heap_pgalloc) {
97                 nvmap_usecount_inc(h);
98                 nvmap_heap_free(h->carveout);
99                 goto out;
100         }
101
102         nr_page = DIV_ROUND_UP(h->size, PAGE_SIZE);
103
104         BUG_ON(h->size & ~PAGE_MASK);
105         BUG_ON(!h->pgalloc.pages);
106
107         nvmap_mru_remove(nvmap_get_share_from_dev(dev), h);
108
109         /* Restore page attributes. */
110         if (h->flags == NVMAP_HANDLE_WRITE_COMBINE ||
111             h->flags == NVMAP_HANDLE_UNCACHEABLE ||
112             h->flags == NVMAP_HANDLE_INNER_CACHEABLE)
113                 set_pages_array_wb(h->pgalloc.pages, nr_page);
114
115         if (h->pgalloc.area)
116                 tegra_iovmm_free_vm(h->pgalloc.area);
117
118         for (i = 0; i < nr_page; i++)
119                 __free_page(h->pgalloc.pages[i]);
120
121         altfree(h->pgalloc.pages, nr_page * sizeof(struct page *));
122
123 out:
124         kfree(h);
125 }
126
127 static struct page *nvmap_alloc_pages_exact(gfp_t gfp, size_t size)
128 {
129         struct page *page, *p, *e;
130         unsigned int order;
131
132         size = PAGE_ALIGN(size);
133         order = get_order(size);
134         page = alloc_pages(gfp, order);
135
136         if (!page)
137                 return NULL;
138
139         split_page(page, order);
140         e = page + (1 << order);
141         for (p = page + (size >> PAGE_SHIFT); p < e; p++)
142                 __free_page(p);
143
144         return page;
145 }
146
147 static int handle_page_alloc(struct nvmap_client *client,
148                              struct nvmap_handle *h, bool contiguous)
149 {
150         size_t size = PAGE_ALIGN(h->size);
151         unsigned int nr_page = size >> PAGE_SHIFT;
152         pgprot_t prot;
153         unsigned int i = 0;
154         struct page **pages;
155
156         pages = altalloc(nr_page * sizeof(*pages));
157         if (!pages)
158                 return -ENOMEM;
159
160         prot = nvmap_pgprot(h, pgprot_kernel);
161
162 #ifdef CONFIG_NVMAP_ALLOW_SYSMEM
163         if (nr_page == 1)
164                 contiguous = true;
165 #endif
166
167         h->pgalloc.area = NULL;
168         if (contiguous) {
169                 struct page *page;
170                 page = nvmap_alloc_pages_exact(GFP_NVMAP, size);
171                 if (!page)
172                         goto fail;
173
174                 for (i = 0; i < nr_page; i++)
175                         pages[i] = nth_page(page, i);
176
177         } else {
178                 for (i = 0; i < nr_page; i++) {
179                         pages[i] = nvmap_alloc_pages_exact(GFP_NVMAP,
180                                 PAGE_SIZE);
181                         if (!pages[i])
182                                 goto fail;
183                 }
184
185 #ifndef CONFIG_NVMAP_RECLAIM_UNPINNED_VM
186                 h->pgalloc.area = tegra_iovmm_create_vm(client->share->iovmm,
187                                         NULL, size, h->align, prot,
188                                         h->pgalloc.iovm_addr);
189                 if (!h->pgalloc.area)
190                         goto fail;
191
192                 h->pgalloc.dirty = true;
193 #endif
194         }
195
196         /* Update the pages mapping in kernel page table. */
197         if (h->flags == NVMAP_HANDLE_WRITE_COMBINE)
198                 set_pages_array_wc(pages, nr_page);
199         else if (h->flags == NVMAP_HANDLE_UNCACHEABLE)
200                 set_pages_array_uc(pages, nr_page);
201         else if (h->flags == NVMAP_HANDLE_INNER_CACHEABLE)
202                 set_pages_array_iwb(pages, nr_page);
203
204         h->size = size;
205         h->pgalloc.pages = pages;
206         h->pgalloc.contig = contiguous;
207         INIT_LIST_HEAD(&h->pgalloc.mru_list);
208         return 0;
209
210 fail:
211         while (i--)
212                 __free_page(pages[i]);
213         altfree(pages, nr_page * sizeof(*pages));
214         wmb();
215         return -ENOMEM;
216 }
217
218 static void alloc_handle(struct nvmap_client *client,
219                          struct nvmap_handle *h, unsigned int type)
220 {
221         BUG_ON(type & (type - 1));
222
223 #ifdef CONFIG_NVMAP_CONVERT_CARVEOUT_TO_IOVMM
224 #define __NVMAP_HEAP_CARVEOUT   (NVMAP_HEAP_CARVEOUT_IRAM | NVMAP_HEAP_CARVEOUT_VPR)
225 #define __NVMAP_HEAP_IOVMM      (NVMAP_HEAP_IOVMM | NVMAP_HEAP_CARVEOUT_GENERIC)
226         if (type & NVMAP_HEAP_CARVEOUT_GENERIC) {
227 #ifdef CONFIG_NVMAP_ALLOW_SYSMEM
228                 if (h->size <= PAGE_SIZE) {
229                         PR_INFO("###CARVEOUT CONVERTED TO SYSMEM "
230                                 "0x%x bytes %s(%d)###\n",
231                                 h->size, current->comm, current->pid);
232                         goto sysheap;
233                 }
234 #endif
235                 PR_INFO("###CARVEOUT CONVERTED TO IOVM "
236                         "0x%x bytes %s(%d)###\n",
237                         h->size, current->comm, current->pid);
238         }
239 #else
240 #define __NVMAP_HEAP_CARVEOUT   NVMAP_HEAP_CARVEOUT_MASK
241 #define __NVMAP_HEAP_IOVMM      NVMAP_HEAP_IOVMM
242 #endif
243
244         if (type & __NVMAP_HEAP_CARVEOUT) {
245                 struct nvmap_heap_block *b;
246 #ifdef CONFIG_NVMAP_CONVERT_CARVEOUT_TO_IOVMM
247                 PR_INFO("###IRAM REQUEST RETAINED "
248                         "0x%x bytes %s(%d)###\n",
249                         h->size, current->comm, current->pid);
250 #endif
251                 /* Protect handle from relocation */
252                 nvmap_usecount_inc(h);
253
254                 b = nvmap_carveout_alloc(client, h, type);
255                 if (b) {
256                         h->heap_pgalloc = false;
257                         h->alloc = true;
258                         nvmap_carveout_commit_add(client,
259                                 nvmap_heap_to_arg(nvmap_block_to_heap(b)),
260                                 h->size);
261                 }
262                 nvmap_usecount_dec(h);
263
264         } else if (type & __NVMAP_HEAP_IOVMM) {
265                 size_t reserved = PAGE_ALIGN(h->size);
266                 int commit = 0;
267                 int ret;
268
269                 /* increment the committed IOVM space prior to allocation
270                  * to avoid race conditions with other threads simultaneously
271                  * allocating. */
272                 commit = atomic_add_return(reserved,
273                                             &client->iovm_commit);
274
275                 if (commit < client->iovm_limit)
276                         ret = handle_page_alloc(client, h, false);
277                 else
278                         ret = -ENOMEM;
279
280                 if (!ret) {
281                         h->heap_pgalloc = true;
282                         h->alloc = true;
283                 } else {
284                         atomic_sub(reserved, &client->iovm_commit);
285                 }
286
287         } else if (type & NVMAP_HEAP_SYSMEM) {
288 #if defined(CONFIG_NVMAP_CONVERT_CARVEOUT_TO_IOVMM) && \
289         defined(CONFIG_NVMAP_ALLOW_SYSMEM)
290 sysheap:
291 #endif
292                 if (handle_page_alloc(client, h, true) == 0) {
293                         BUG_ON(!h->pgalloc.contig);
294                         h->heap_pgalloc = true;
295                         h->alloc = true;
296                 }
297         }
298 }
299
300 /* small allocations will try to allocate from generic OS memory before
301  * any of the limited heaps, to increase the effective memory for graphics
302  * allocations, and to reduce fragmentation of the graphics heaps with
303  * sub-page splinters */
304 static const unsigned int heap_policy_small[] = {
305         NVMAP_HEAP_CARVEOUT_VPR,
306         NVMAP_HEAP_CARVEOUT_IRAM,
307 #ifdef CONFIG_NVMAP_ALLOW_SYSMEM
308         NVMAP_HEAP_SYSMEM,
309 #endif
310         NVMAP_HEAP_CARVEOUT_MASK,
311         NVMAP_HEAP_IOVMM,
312         0,
313 };
314
315 static const unsigned int heap_policy_large[] = {
316         NVMAP_HEAP_CARVEOUT_VPR,
317         NVMAP_HEAP_CARVEOUT_IRAM,
318         NVMAP_HEAP_IOVMM,
319         NVMAP_HEAP_CARVEOUT_MASK,
320 #ifdef CONFIG_NVMAP_ALLOW_SYSMEM
321         NVMAP_HEAP_SYSMEM,
322 #endif
323         0,
324 };
325
326 /* Do not override single page policy if there is not much space to
327 avoid invoking system oom killer. */
328 #define NVMAP_SMALL_POLICY_SYSMEM_THRESHOLD 50000000
329
330 int nvmap_alloc_handle_id(struct nvmap_client *client,
331                           unsigned long id, unsigned int heap_mask,
332                           size_t align, unsigned int flags)
333 {
334         struct nvmap_handle *h = NULL;
335         const unsigned int *alloc_policy;
336         int nr_page;
337         int err = -ENOMEM;
338
339         h = nvmap_get_handle_id(client, id);
340
341         if (!h)
342                 return -EINVAL;
343
344         if (h->alloc)
345                 goto out;
346
347         h->userflags = flags;
348         nr_page = ((h->size + PAGE_SIZE - 1) >> PAGE_SHIFT);
349         h->secure = !!(flags & NVMAP_HANDLE_SECURE);
350         h->flags = (flags & NVMAP_HANDLE_CACHE_FLAG);
351         h->align = max_t(size_t, align, L1_CACHE_BYTES);
352
353 #ifndef CONFIG_TEGRA_IOVMM
354         if (heap_mask & NVMAP_HEAP_IOVMM) {
355                 heap_mask &= NVMAP_HEAP_IOVMM;
356                 heap_mask |= NVMAP_HEAP_CARVEOUT_GENERIC;
357         }
358 #endif
359 #ifndef CONFIG_NVMAP_CONVERT_CARVEOUT_TO_IOVMM
360 #ifdef CONFIG_NVMAP_ALLOW_SYSMEM
361         /* Allow single pages allocations in system memory to save
362          * carveout space and avoid extra iovm mappings */
363         if (nr_page == 1) {
364                 if (heap_mask & NVMAP_HEAP_IOVMM)
365                         heap_mask |= NVMAP_HEAP_SYSMEM;
366                 else if (heap_mask & NVMAP_HEAP_CARVEOUT_GENERIC) {
367                         /* Calculate size of free physical pages
368                          * managed by kernel */
369                         unsigned long freeMem =
370                                 (global_page_state(NR_FREE_PAGES) +
371                                 global_page_state(NR_FILE_PAGES) -
372                                 total_swapcache_pages) << PAGE_SHIFT;
373
374                         if (freeMem > NVMAP_SMALL_POLICY_SYSMEM_THRESHOLD)
375                                 heap_mask |= NVMAP_HEAP_SYSMEM;
376                 }
377         }
378 #endif
379
380         /* This restriction is deprecated as alignments greater than
381            PAGE_SIZE are now correctly handled, but it is retained for
382            AP20 compatibility. */
383         if (h->align > PAGE_SIZE)
384                 heap_mask &= NVMAP_HEAP_CARVEOUT_MASK;
385 #endif
386         /* secure allocations can only be served from secure heaps */
387         if (h->secure)
388                 heap_mask &= NVMAP_SECURE_HEAPS;
389
390         if (!heap_mask) {
391                 err = -EINVAL;
392                 goto out;
393         }
394
395         alloc_policy = (nr_page == 1) ? heap_policy_small : heap_policy_large;
396
397         while (!h->alloc && *alloc_policy) {
398                 unsigned int heap_type;
399
400                 heap_type = *alloc_policy++;
401                 heap_type &= heap_mask;
402
403                 if (!heap_type)
404                         continue;
405
406                 heap_mask &= ~heap_type;
407
408                 while (heap_type && !h->alloc) {
409                         unsigned int heap;
410
411                         /* iterate possible heaps MSB-to-LSB, since higher-
412                          * priority carveouts will have higher usage masks */
413                         heap = 1 << __fls(heap_type);
414                         alloc_handle(client, h, heap);
415                         heap_type &= ~heap;
416                 }
417         }
418
419 out:
420         err = (h->alloc) ? 0 : err;
421         nvmap_handle_put(h);
422         return err;
423 }
424
425 void nvmap_free_handle_id(struct nvmap_client *client, unsigned long id)
426 {
427         struct nvmap_handle_ref *ref;
428         struct nvmap_handle *h;
429         int pins;
430
431         nvmap_ref_lock(client);
432
433         ref = _nvmap_validate_id_locked(client, id);
434         if (!ref) {
435                 nvmap_ref_unlock(client);
436                 return;
437         }
438
439         BUG_ON(!ref->handle);
440         h = ref->handle;
441
442         if (atomic_dec_return(&ref->dupes)) {
443                 nvmap_ref_unlock(client);
444                 goto out;
445         }
446
447         smp_rmb();
448         pins = atomic_read(&ref->pin);
449         rb_erase(&ref->node, &client->handle_refs);
450
451         if (h->alloc && h->heap_pgalloc && !h->pgalloc.contig)
452                 atomic_sub(h->size, &client->iovm_commit);
453
454         if (h->alloc && !h->heap_pgalloc) {
455                 mutex_lock(&h->lock);
456                 nvmap_carveout_commit_subtract(client,
457                         nvmap_heap_to_arg(nvmap_block_to_heap(h->carveout)),
458                         h->size);
459                 mutex_unlock(&h->lock);
460         }
461
462         nvmap_ref_unlock(client);
463
464         if (pins)
465                 nvmap_err(client, "%s freeing pinned handle %p\n",
466                           current->group_leader->comm, h);
467
468         while (pins--)
469                 nvmap_unpin_handles(client, &ref->handle, 1);
470
471         if (h->owner == client)
472                 h->owner = NULL;
473
474         kfree(ref);
475
476 out:
477         BUG_ON(!atomic_read(&h->ref));
478         nvmap_handle_put(h);
479 }
480
481 static void add_handle_ref(struct nvmap_client *client,
482                            struct nvmap_handle_ref *ref)
483 {
484         struct rb_node **p, *parent = NULL;
485
486         nvmap_ref_lock(client);
487         p = &client->handle_refs.rb_node;
488         while (*p) {
489                 struct nvmap_handle_ref *node;
490                 parent = *p;
491                 node = rb_entry(parent, struct nvmap_handle_ref, node);
492                 if (ref->handle > node->handle)
493                         p = &parent->rb_right;
494                 else
495                         p = &parent->rb_left;
496         }
497         rb_link_node(&ref->node, parent, p);
498         rb_insert_color(&ref->node, &client->handle_refs);
499         nvmap_ref_unlock(client);
500 }
501
502 struct nvmap_handle_ref *nvmap_create_handle(struct nvmap_client *client,
503                                              size_t size)
504 {
505         struct nvmap_handle *h;
506         struct nvmap_handle_ref *ref = NULL;
507
508         if (!client)
509                 return ERR_PTR(-EINVAL);
510
511         if (!size)
512                 return ERR_PTR(-EINVAL);
513
514         h = kzalloc(sizeof(*h), GFP_KERNEL);
515         if (!h)
516                 return ERR_PTR(-ENOMEM);
517
518         ref = kzalloc(sizeof(*ref), GFP_KERNEL);
519         if (!ref) {
520                 kfree(h);
521                 return ERR_PTR(-ENOMEM);
522         }
523
524         atomic_set(&h->ref, 1);
525         atomic_set(&h->pin, 0);
526         h->owner = client;
527         h->dev = client->dev;
528         BUG_ON(!h->owner);
529         h->size = h->orig_size = size;
530         h->flags = NVMAP_HANDLE_WRITE_COMBINE;
531         mutex_init(&h->lock);
532
533         nvmap_handle_add(client->dev, h);
534
535         atomic_set(&ref->dupes, 1);
536         ref->handle = h;
537         atomic_set(&ref->pin, 0);
538         add_handle_ref(client, ref);
539         return ref;
540 }
541
542 struct nvmap_handle_ref *nvmap_duplicate_handle_id(struct nvmap_client *client,
543                                                    unsigned long id)
544 {
545         struct nvmap_handle_ref *ref = NULL;
546         struct nvmap_handle *h = NULL;
547
548         BUG_ON(!client || client->dev != nvmap_dev);
549         /* on success, the reference count for the handle should be
550          * incremented, so the success paths will not call nvmap_handle_put */
551         h = nvmap_validate_get(client, id);
552
553         if (!h) {
554                 nvmap_debug(client, "%s duplicate handle failed\n",
555                             current->group_leader->comm);
556                 return ERR_PTR(-EPERM);
557         }
558
559         if (!h->alloc) {
560                 nvmap_err(client, "%s duplicating unallocated handle\n",
561                           current->group_leader->comm);
562                 nvmap_handle_put(h);
563                 return ERR_PTR(-EINVAL);
564         }
565
566         nvmap_ref_lock(client);
567         ref = _nvmap_validate_id_locked(client, (unsigned long)h);
568
569         if (ref) {
570                 /* handle already duplicated in client; just increment
571                  * the reference count rather than re-duplicating it */
572                 atomic_inc(&ref->dupes);
573                 nvmap_ref_unlock(client);
574                 return ref;
575         }
576
577         nvmap_ref_unlock(client);
578
579         /* verify that adding this handle to the process' access list
580          * won't exceed the IOVM limit */
581         if (h->heap_pgalloc && !h->pgalloc.contig) {
582                 int oc;
583                 oc = atomic_add_return(h->size, &client->iovm_commit);
584                 if (oc > client->iovm_limit && !client->super) {
585                         atomic_sub(h->size, &client->iovm_commit);
586                         nvmap_handle_put(h);
587                         nvmap_err(client, "duplicating %p in %s over-commits"
588                                   " IOVMM space\n", (void *)id,
589                                   current->group_leader->comm);
590                         return ERR_PTR(-ENOMEM);
591                 }
592         }
593
594         ref = kzalloc(sizeof(*ref), GFP_KERNEL);
595         if (!ref) {
596                 nvmap_handle_put(h);
597                 return ERR_PTR(-ENOMEM);
598         }
599
600         if (!h->heap_pgalloc) {
601                 mutex_lock(&h->lock);
602                 nvmap_carveout_commit_add(client,
603                         nvmap_heap_to_arg(nvmap_block_to_heap(h->carveout)),
604                         h->size);
605                 mutex_unlock(&h->lock);
606         }
607
608         atomic_set(&ref->dupes, 1);
609         ref->handle = h;
610         atomic_set(&ref->pin, 0);
611         add_handle_ref(client, ref);
612         return ref;
613 }