rk: temp revert rk change
[firefly-linux-kernel-4.4.55.git] / drivers / gpu / ion / ion_system_heap.c
1 /*
2  * drivers/gpu/ion/ion_system_heap.c
3  *
4  * Copyright (C) 2011 Google, Inc.
5  *
6  * This software is licensed under the terms of the GNU General Public
7  * License version 2, as published by the Free Software Foundation, and
8  * may be copied, distributed, and modified under those terms.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  */
16
17 #include <linux/err.h>
18 #include <linux/ion.h>
19 #include <linux/mm.h>
20 #include <linux/scatterlist.h>
21 #include <linux/slab.h>
22 #include <linux/vmalloc.h>
23 #include "ion_priv.h"
24
25 static int ion_system_heap_allocate(struct ion_heap *heap,
26                                      struct ion_buffer *buffer,
27                                      unsigned long size, unsigned long align,
28                                      unsigned long flags)
29 {
30         buffer->priv_virt = vmalloc_user(size);
31         if (!buffer->priv_virt)
32                 return -ENOMEM;
33         return 0;
34 }
35
36 void ion_system_heap_free(struct ion_buffer *buffer)
37 {
38         vfree(buffer->priv_virt);
39 }
40
41 struct scatterlist *ion_system_heap_map_dma(struct ion_heap *heap,
42                                             struct ion_buffer *buffer)
43 {
44         struct scatterlist *sglist;
45         struct page *page;
46         int i;
47         int npages = PAGE_ALIGN(buffer->size) / PAGE_SIZE;
48         void *vaddr = buffer->priv_virt;
49
50         sglist = vmalloc(npages * sizeof(struct scatterlist));
51         if (!sglist)
52                 return ERR_PTR(-ENOMEM);
53         memset(sglist, 0, npages * sizeof(struct scatterlist));
54         sg_init_table(sglist, npages);
55         for (i = 0; i < npages; i++) {
56                 page = vmalloc_to_page(vaddr);
57                 if (!page)
58                         goto end;
59                 sg_set_page(&sglist[i], page, PAGE_SIZE, 0);
60                 vaddr += PAGE_SIZE;
61         }
62         /* XXX do cache maintenance for dma? */
63         return sglist;
64 end:
65         vfree(sglist);
66         return NULL;
67 }
68
69 void ion_system_heap_unmap_dma(struct ion_heap *heap,
70                                struct ion_buffer *buffer)
71 {
72         /* XXX undo cache maintenance for dma? */
73         if (buffer->sglist)
74                 vfree(buffer->sglist);
75 }
76
77 void *ion_system_heap_map_kernel(struct ion_heap *heap,
78                                  struct ion_buffer *buffer)
79 {
80         return buffer->priv_virt;
81 }
82
83 void ion_system_heap_unmap_kernel(struct ion_heap *heap,
84                                   struct ion_buffer *buffer)
85 {
86 }
87
88 int ion_system_heap_map_user(struct ion_heap *heap, struct ion_buffer *buffer,
89                              struct vm_area_struct *vma)
90 {
91         return remap_vmalloc_range(vma, buffer->priv_virt, vma->vm_pgoff);
92 }
93
94 static struct ion_heap_ops vmalloc_ops = {
95         .allocate = ion_system_heap_allocate,
96         .free = ion_system_heap_free,
97         .map_dma = ion_system_heap_map_dma,
98         .unmap_dma = ion_system_heap_unmap_dma,
99         .map_kernel = ion_system_heap_map_kernel,
100         .unmap_kernel = ion_system_heap_unmap_kernel,
101         .map_user = ion_system_heap_map_user,
102 };
103
104 struct ion_heap *ion_system_heap_create(struct ion_platform_heap *unused)
105 {
106         struct ion_heap *heap;
107
108         heap = kzalloc(sizeof(struct ion_heap), GFP_KERNEL);
109         if (!heap)
110                 return ERR_PTR(-ENOMEM);
111         heap->ops = &vmalloc_ops;
112         heap->type = ION_HEAP_TYPE_SYSTEM;
113         return heap;
114 }
115
116 void ion_system_heap_destroy(struct ion_heap *heap)
117 {
118         kfree(heap);
119 }
120
121 static int ion_system_contig_heap_allocate(struct ion_heap *heap,
122                                            struct ion_buffer *buffer,
123                                            unsigned long len,
124                                            unsigned long align,
125                                            unsigned long flags)
126 {
127         buffer->priv_virt = kzalloc(len, GFP_KERNEL);
128         if (!buffer->priv_virt)
129                 return -ENOMEM;
130         return 0;
131 }
132
133 void ion_system_contig_heap_free(struct ion_buffer *buffer)
134 {
135         kfree(buffer->priv_virt);
136 }
137
138 static int ion_system_contig_heap_phys(struct ion_heap *heap,
139                                        struct ion_buffer *buffer,
140                                        ion_phys_addr_t *addr, size_t *len)
141 {
142         *addr = virt_to_phys(buffer->priv_virt);
143         *len = buffer->size;
144         return 0;
145 }
146
147 struct scatterlist *ion_system_contig_heap_map_dma(struct ion_heap *heap,
148                                                    struct ion_buffer *buffer)
149 {
150         struct scatterlist *sglist;
151
152         sglist = vmalloc(sizeof(struct scatterlist));
153         if (!sglist)
154                 return ERR_PTR(-ENOMEM);
155         sg_init_table(sglist, 1);
156         sg_set_page(sglist, virt_to_page(buffer->priv_virt), buffer->size, 0);
157         return sglist;
158 }
159
160 int ion_system_contig_heap_map_user(struct ion_heap *heap,
161                                     struct ion_buffer *buffer,
162                                     struct vm_area_struct *vma)
163 {
164         unsigned long pfn = __phys_to_pfn(virt_to_phys(buffer->priv_virt));
165         return remap_pfn_range(vma, vma->vm_start, pfn + vma->vm_pgoff,
166                                vma->vm_end - vma->vm_start,
167                                vma->vm_page_prot);
168
169 }
170
171 static struct ion_heap_ops kmalloc_ops = {
172         .allocate = ion_system_contig_heap_allocate,
173         .free = ion_system_contig_heap_free,
174         .phys = ion_system_contig_heap_phys,
175         .map_dma = ion_system_contig_heap_map_dma,
176         .unmap_dma = ion_system_heap_unmap_dma,
177         .map_kernel = ion_system_heap_map_kernel,
178         .unmap_kernel = ion_system_heap_unmap_kernel,
179         .map_user = ion_system_contig_heap_map_user,
180 };
181
182 struct ion_heap *ion_system_contig_heap_create(struct ion_platform_heap *unused)
183 {
184         struct ion_heap *heap;
185
186         heap = kzalloc(sizeof(struct ion_heap), GFP_KERNEL);
187         if (!heap)
188                 return ERR_PTR(-ENOMEM);
189         heap->ops = &kmalloc_ops;
190         heap->type = ION_HEAP_TYPE_SYSTEM_CONTIG;
191         return heap;
192 }
193
194 void ion_system_contig_heap_destroy(struct ion_heap *heap)
195 {
196         kfree(heap);
197 }
198